mirror of https://github.com/abpframework/abp.git
1 changed files with 347 additions and 0 deletions
@ -0,0 +1,347 @@ |
|||||
|
# Quick Start |
||||
|
|
||||
|
````json |
||||
|
//[doc-params] |
||||
|
{ |
||||
|
"UI": ["MVC", "BlazorServer", "NG"], |
||||
|
"DB": ["EF", "Mongo"] |
||||
|
} |
||||
|
```` |
||||
|
|
||||
|
This is a single-part quick-start tutorial to build a simple todo application with the ABP Framework. Here's a screenshot from the final application: |
||||
|
|
||||
|
 |
||||
|
|
||||
|
You can find the source code of the completed application [here](TODO: sample's url???). |
||||
|
|
||||
|
## Pre-Requirements |
||||
|
|
||||
|
* An IDE (e.g. [Visual Studio](https://visualstudio.microsoft.com/vs/)) that supports [.NET 6.0+](https://dotnet.microsoft.com/download/dotnet) development. |
||||
|
|
||||
|
{{if DB=="Mongo"}} |
||||
|
|
||||
|
* [MongoDB Server 4.0+](https://docs.mongodb.com/manual/administration/install-community/) |
||||
|
|
||||
|
{{end}} |
||||
|
|
||||
|
{{if UI=="NG"}} |
||||
|
|
||||
|
* [Node v14.x](https://nodejs.org/) |
||||
|
|
||||
|
{{end}} |
||||
|
|
||||
|
## Creating a New Solution |
||||
|
|
||||
|
In this tutorial, we will use the [ABP CLI](../../CLI.md) to create the sample application with the ABP Framework. You can run the following command in a command-line terminal to install the **ABP CLI**, if you haven't installed it yet: |
||||
|
|
||||
|
````bash |
||||
|
dotnet tool install -g Volo.Abp.Cli |
||||
|
```` |
||||
|
|
||||
|
Then create an empty folder, open a command-line terminal and execute the following command in the terminal: |
||||
|
|
||||
|
````bash |
||||
|
abp new TodoApp -t app-nolayers{{if UI=="BlazorServer"}} -u blazor-server{{else if UI=="NG"}} -u angular{{end}}{{if DB=="Mongo"}} -d mongodb{{end}} |
||||
|
```` |
||||
|
|
||||
|
{{if UI=="NG"}} |
||||
|
|
||||
|
This will create a new solution with a single-project, named *TodoApp* with `angular` and `aspnet-core` folders. Once the solution is ready, open the solution in your favorite IDE. |
||||
|
|
||||
|
{{else}} |
||||
|
|
||||
|
This will create a new solution with a single-project, named *TodoApp*. Once the solution is ready, open it in your favorite IDE. |
||||
|
|
||||
|
{{end}} |
||||
|
|
||||
|
### Create the Database |
||||
|
|
||||
|
You can run the following command in the directory of your project to create the database and seed the initial data: |
||||
|
|
||||
|
```bash |
||||
|
dotnet run --migrate-database |
||||
|
``` |
||||
|
|
||||
|
This command will create the database and seed the initial data for you. Then you can run the application. |
||||
|
|
||||
|
### Run the Application |
||||
|
|
||||
|
{{if UI=="MVC" || UI=="BlazorServer"}} |
||||
|
|
||||
|
It is good to run the application before starting the development. Running the application is pretty straigth-forward, you can run the application with any IDE that supports .NET or by running the `dotnet run` CLI command in the directory of your project to see the initial UI: |
||||
|
|
||||
|
{{else if UI=="NG"}} |
||||
|
|
||||
|
It is good to run the application before starting the development. The solution has two main applications: |
||||
|
|
||||
|
* `TodoApp` (in the .NET solution) host the server-side HTTP API, so Angular application can consume it. (server-side application) |
||||
|
* `angular` folder contains the Angular application. (client-side application) |
||||
|
|
||||
|
Firstly, run the `TodoApp` project in your favorite IDE (or run the `dotnet run` CLI command on your project directory) to see the server-side HTTP API on the [Swagger UI](https://swagger.io/tools/swagger-ui/): |
||||
|
|
||||
|
 |
||||
|
|
||||
|
You can explore and test your HTTP API with this UI. If it works, we can run the Angular client application. |
||||
|
|
||||
|
First, run the following command (or `yarn install`) to restore the NPM packages: |
||||
|
|
||||
|
````bash |
||||
|
npm install |
||||
|
```` |
||||
|
|
||||
|
It will take some time to install all packages. Then you can run the application using the following (or `yarn start`) command: |
||||
|
|
||||
|
````bash |
||||
|
npm start |
||||
|
```` |
||||
|
|
||||
|
This command takes time, but eventually runs and opens the application in your default browser: |
||||
|
|
||||
|
{{end}} |
||||
|
|
||||
|
 |
||||
|
|
||||
|
You can click on the *Login* button, use `admin` as the username and `1q2w3E*` as the password to login to the application. |
||||
|
|
||||
|
All ready. We can start coding! |
||||
|
|
||||
|
## Defining Entities |
||||
|
|
||||
|
This application will have a single [entity](../../../Entities.md) and we can start by creating it. So, create a new `TodoItem` class under the **Entities** folder of the project. |
||||
|
|
||||
|
````csharp |
||||
|
using Volo.Abp.Domain.Entities; |
||||
|
|
||||
|
namespace TodoApp.Entities; |
||||
|
|
||||
|
public class TodoItem : BasicAggregateRoot<Guid> |
||||
|
{ |
||||
|
public string Text { get; set; } |
||||
|
} |
||||
|
```` |
||||
|
|
||||
|
`BasicAggregateRoot` is the simplest base class to create root entities, and `Guid` is the primary key (`Id`) of the entity here. |
||||
|
|
||||
|
## Database Integration |
||||
|
|
||||
|
{{if DB=="EF"}} |
||||
|
|
||||
|
Next step is to setup the [Entity Framework Core](../../../Entity-Framework-Core.md) configuration. |
||||
|
|
||||
|
### Mapping Configuration |
||||
|
|
||||
|
Open the `TodoAppDbContext` class (it's under the **Data** folder) and add a new `DbSet` property to this class: |
||||
|
|
||||
|
````csharp |
||||
|
public DbSet<TodoItem> TodoItems { get; set; } |
||||
|
```` |
||||
|
|
||||
|
Then navigate to the `OnModelCreating` method in the same class and add the mapping code for the `TodoItem ` entity: |
||||
|
|
||||
|
````csharp |
||||
|
protected override void OnModelCreating(ModelBuilder builder) |
||||
|
{ |
||||
|
base.OnModelCreating(builder); |
||||
|
|
||||
|
/* Include modules to your migration db context */ |
||||
|
|
||||
|
builder.ConfigurePermissionManagement(); |
||||
|
... |
||||
|
|
||||
|
/* Configure your own tables/entities inside here */ |
||||
|
builder.Entity<TodoItem>(b => |
||||
|
{ |
||||
|
b.ToTable("TodoItems"); |
||||
|
}); |
||||
|
} |
||||
|
```` |
||||
|
|
||||
|
We've mapped the `TodoItem` entity to the `TodoItems` table in the database. The next step is creating a migration and apply the changes to the database. |
||||
|
|
||||
|
### Code First Migrations |
||||
|
|
||||
|
The startup solution is configured to use Entity Framework Core [Code First Migrations](https://docs.microsoft.com/en-us/ef/core/managing-schemas/migrations). Since we've changed the database mapping configuration, we should create a new migration and apply changes to the database. |
||||
|
|
||||
|
Open a command-line terminal in the directory of your project and type the following command: |
||||
|
|
||||
|
````bash |
||||
|
dotnet ef migrations add Added_TodoItem |
||||
|
```` |
||||
|
|
||||
|
This will add a new migration class to the project: |
||||
|
|
||||
|
 TODO: add this screenshot??? |
||||
|
|
||||
|
You can apply changes to the database using the following command, in the same command-line terminal: |
||||
|
|
||||
|
````bash |
||||
|
dotnet ef database update |
||||
|
```` |
||||
|
|
||||
|
{{else if DB=="Mongo"}} |
||||
|
|
||||
|
Next step is to setup the [MongoDB](../../../MongoDB.md) configuration. Open the `TodoAppMongoDbContext` class (it's under the **Data** folder) in your project and make the following changes: |
||||
|
|
||||
|
1. Add a new property to the class: |
||||
|
|
||||
|
````csharp |
||||
|
public IMongoCollection<TodoItem> TodoItems => Collection<TodoItem>(); |
||||
|
```` |
||||
|
|
||||
|
2. Add the following code inside the `CreateModel` method: |
||||
|
|
||||
|
````csharp |
||||
|
modelBuilder.Entity<TodoItem>(b => |
||||
|
{ |
||||
|
b.CollectionName = "TodoItems"; |
||||
|
}); |
||||
|
```` |
||||
|
|
||||
|
{{end}} |
||||
|
|
||||
|
After the database integrations, now we can start to create application service methods and implement our use-cases. |
||||
|
|
||||
|
## Creating the Application Service Interface |
||||
|
|
||||
|
An [Application Service](../../Application-Services.md) is used to perform the use cases of the application. We need to perform the following use cases in this application: |
||||
|
|
||||
|
* Get the list of the todo items |
||||
|
* Create a new todo item |
||||
|
* Delete an existing todo item |
||||
|
|
||||
|
Let's start with defining an interface for the application service. Create a new `ITodoAppService` interface under the **Services** folder, as shown below: |
||||
|
|
||||
|
```csharp |
||||
|
using TodoApp.Services.Dtos; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
|
||||
|
namespace TodoApp.Services; |
||||
|
|
||||
|
public interface ITodoAppService : IApplicationService |
||||
|
{ |
||||
|
Task<List<TodoItemDto>> GetListAsync(); |
||||
|
Task<TodoItemDto> CreateAsync(string text); |
||||
|
Task DeleteAsync(Guid id); |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
## Creating the Data Transfer Object (DTO) |
||||
|
|
||||
|
`GetListAsync` and `CreateAsync` methods return `TodoItemDto`. `ApplicationService` typically gets and returns DTOs ([Data Transfer Objects](../../../Data-Transfer-Objects.md)) instead of entities but we haven't created it yet. So, create a new `TodoItemDto` class under the **Dtos** folder (it's under the **Services** folder): |
||||
|
|
||||
|
```csharp |
||||
|
namespace TodoApp.Services.Dtos; |
||||
|
|
||||
|
public class TodoItemDto |
||||
|
{ |
||||
|
public Guid Id { get; set; } |
||||
|
public string Text { get; set; } |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
This is a very simple DTO class that have the same properties with our `TodoItem` entity. We are ready to implement the `ITodoAppService`. |
||||
|
|
||||
|
## Application Service Implementation |
||||
|
|
||||
|
Create a `TodoAppService` class under the **Services** folder of your project, as shown below: |
||||
|
|
||||
|
```csharp |
||||
|
using TodoApp.Entities; |
||||
|
using Volo.Abp.Application.Services; |
||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
|
||||
|
namespace TodoApp.Services; |
||||
|
|
||||
|
public class TodoAppService : ApplicationService, ITodoAppService |
||||
|
{ |
||||
|
private readonly IRepository<TodoItem, Guid> _todoItemRepository; |
||||
|
|
||||
|
public TodoAppService(IRepository<TodoItem, Guid> todoItemRepository) |
||||
|
{ |
||||
|
_todoItemRepository = todoItemRepository; |
||||
|
} |
||||
|
|
||||
|
// TODO: Implement the methods here... |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
This class inherits from the `ApplicationService` class of the ABP Framework and implements the `ITodoAppService` that created in the [Creating the Application Service Interface](#creating-the-application-service-interface) section. ABP provides default generic [repositories](../../../Repositories.md) for the entities. We can use them to perform the fundamental database operations. This class [injects](../../../Dependency-Injection.md) `IRepository<TodoItem, Guid>`, which is the default repository for the `TodoItem` entity. We will use it to implement the use cases described before. |
||||
|
|
||||
|
### Getting Todo Items |
||||
|
|
||||
|
Let's start by implementing the `GetListAsync` method: |
||||
|
|
||||
|
````csharp |
||||
|
public async Task<List<TodoItemDto>> GetListAsync() |
||||
|
{ |
||||
|
var items = await _todoItemRepository.GetListAsync(); |
||||
|
return items |
||||
|
.Select(item => new TodoItemDto |
||||
|
{ |
||||
|
Id = item.Id, |
||||
|
Text = item.Text |
||||
|
}).ToList(); |
||||
|
} |
||||
|
```` |
||||
|
|
||||
|
We are simply getting the complete `TodoItem` list from the database, mapping them to `TodoItemDto` objects and returning as the result. |
||||
|
|
||||
|
#### Creating a New Todo Item |
||||
|
|
||||
|
Next method is `CreateAsync` and we can implement it as shown below: |
||||
|
|
||||
|
````csharp |
||||
|
public async Task<TodoItemDto> CreateAsync(string text) |
||||
|
{ |
||||
|
var todoItem = await _todoItemRepository.InsertAsync( |
||||
|
new TodoItem {Text = text} |
||||
|
); |
||||
|
|
||||
|
return new TodoItemDto |
||||
|
{ |
||||
|
Id = todoItem.Id, |
||||
|
Text = todoItem.Text |
||||
|
}; |
||||
|
} |
||||
|
```` |
||||
|
|
||||
|
The repository's `InsertAsync` method inserts the given `TodoItem` to the database and returns the same `TodoItem` object. It also sets the `Id`, so we can use it on the returning object. We are simply returning a `TodoItemDto` by creating from the new `TodoItem` entity. |
||||
|
|
||||
|
#### Deleting a Todo Item |
||||
|
|
||||
|
Finally, we can implement the `DeleteAsync` as the following code block: |
||||
|
|
||||
|
````csharp |
||||
|
public async Task DeleteAsync(Guid id) |
||||
|
{ |
||||
|
await _todoItemRepository.DeleteAsync(id); |
||||
|
} |
||||
|
```` |
||||
|
|
||||
|
The application service is ready to be used from the UI layer. |
||||
|
|
||||
|
## User Interface Layer |
||||
|
|
||||
|
It is time to show the todo items on the UI! Before starting to write the code, it would be good to remember what we are trying to build. Here's a sample screenshot from the final UI: |
||||
|
|
||||
|
 |
||||
|
|
||||
|
{{if UI=="MVC"}} |
||||
|
|
||||
|
{{else if UI=="BlazorServer"}} |
||||
|
|
||||
|
{{else if UI=="NG"}} |
||||
|
|
||||
|
{{end}} |
||||
|
|
||||
|
## Conclusion |
||||
|
|
||||
|
In this tutorial, we've built a very simple application to warm up with the ABP Framework. |
||||
|
|
||||
|
## Source Code |
||||
|
|
||||
|
You can find source code of the completed application [here](https://github.com/abpframework/abp-samples/tree/master/TodoApp). |
||||
|
|
||||
|
## See Also |
||||
|
|
||||
|
* [Web Application Development Tutorial](../Part-1.md) to see a real-life web application development in a layered architecture. |
||||
Loading…
Reference in new issue