diff --git a/docs/en/tutorials/modular-crm/images/visual-studio-application-contracts.png b/docs/en/tutorials/modular-crm/images/visual-studio-application-contracts.png index e7fc6829d9..0368089bff 100644 Binary files a/docs/en/tutorials/modular-crm/images/visual-studio-application-contracts.png and b/docs/en/tutorials/modular-crm/images/visual-studio-application-contracts.png differ diff --git a/docs/en/tutorials/modular-crm/index.md b/docs/en/tutorials/modular-crm/index.md index c39caabc85..8a46d5d507 100644 --- a/docs/en/tutorials/modular-crm/index.md +++ b/docs/en/tutorials/modular-crm/index.md @@ -2,6 +2,8 @@ ABP provides a great infrastructure and tooling to build modular software solutions. In this tutorial, you will learn how to create application modules, compose and communicate them to build a monolith modular web application. +> **This tutorial is focused on modularity. The example application functionality and user interface are intentionally kept simple. If you want to learn real world, full featured application development with ABP, please follow the [Book Store tutorial](../book-store/index.md).** + ## Tutorial Outline This tutorial is organized as the following parts: diff --git a/docs/en/tutorials/modular-crm/part-03.md b/docs/en/tutorials/modular-crm/part-03.md index 57b0f24989..dbce8cbfa7 100644 --- a/docs/en/tutorials/modular-crm/part-03.md +++ b/docs/en/tutorials/modular-crm/part-03.md @@ -238,11 +238,12 @@ After the operation completes, you can check your database to see the new `Produ Now, we will create an [application service](../../framework/architecture/domain-driven-design/application-services.md) to perform some use cases related to products. -### Defining the Application Service Contracts +### Defining the Application Service Contract Return to your IDE (e.g. Visual Studio), open the `ModularCrm.Products` module's .NET solution and create an `IProductAppService` interface under the `ModularCrm.Products.Application.Contracts` project: ````csharp +using System.Collections.Generic; using System.Threading.Tasks; using Volo.Abp.Application.Services; @@ -250,25 +251,49 @@ namespace ModularCrm.Products; public interface IProductAppService : IApplicationService { + Task> GetListAsync(); Task CreateAsync(ProductCreationDto input); } ```` We are defining application service interfaces and [data transfer objects](../../framework/architecture/domain-driven-design/data-transfer-objects.md) in the `Application.Contracts` project. In that way, we can share that contracts with clients without sharing the actual implementation class. -`IProductAppService.CreateAsync` method gets an object of type `ProductCreationDto`. So, we also need to create a `ProductCreationDto` class under the `ModularCrm.Products.Application.Contracts` project: +### Defining Data Transfer Objects + +`GetListAsync` and `.CreateAsync` methods are using `ProductDto` and `ProductCreationDto` that are not defined yet. So, we need to define them. + +Create a `ProductCreationDto` class under the `ModularCrm.Products.Application.Contracts` project: ````csharp +using System.ComponentModel.DataAnnotations; + namespace ModularCrm.Products; public class ProductCreationDto { + [Required] + [StringLength(100)] public string Name { get; set; } + + [Range(0, int.MaxValue)] public int StockCount { get; set; } } ```` -These two files should be located under the `ModularCrm.Products.Application.Contracts` project as shown below: +And create a `ProductDto` class under the `ModularCrm.Products.Application.Contracts` project: + +````csharp +namespace ModularCrm.Products +{ + public class ProductDto + { + public string Name { get; set; } + public int StockCount { get; set; } + } +} +```` + +The new files under the `ModularCrm.Products.Application.Contracts` project are shown below: ![visual-studio-application-contracts](images/visual-studio-application-contracts.png) @@ -278,6 +303,7 @@ Now, we can implement the `IProductAppService` interface. Create a `ProductAppSe ````csharp using System; +using System.Collections.Generic; using System.Threading.Tasks; using Volo.Abp.Domain.Repositories; @@ -292,6 +318,12 @@ public class ProductAppService : ProductsAppService, IProductAppService _productRepository = productRepository; } + public async Task> GetListAsync() + { + var products = await _productRepository.GetListAsync(); + return ObjectMapper.Map, List>(products); + } + public async Task CreateAsync(ProductCreationDto input) { var product = new Product @@ -307,12 +339,28 @@ public class ProductAppService : ProductsAppService, IProductAppService Notice that `ProductAppService` class implements the `IProductAppService` and also inherits from the `ProductsAppService` class. Do not confuse about the naming (`ProductAppService` and `ProductsAppService`). The `ProductsAppService` is a base class. It makes a few configuration for [localization](../../framework/fundamentals/localization.md) and [object mapping](../../framework/infrastructure/object-to-object-mapping.md) (you can see in the `ModularCrm.Products.Application` project). You can inherit all of your application services from that base class. In this way, you can define some common properties and methods to share among all your application services. You can rename the base class if you feel that you may confuse later. -... +#### Object Mapping +`ProductAppService.GetListAsync` method uses the `ObjectMapper` service to convert `Product` entities to `ProductDto` objects. The mapping should be configured. Open the `ProductsApplicationAutoMapperProfile` class in the `ModularCrm.Products.Application` project and change it as the following code block: +````csharp +using AutoMapper; + +namespace ModularCrm.Products; +public class ProductsApplicationAutoMapperProfile : Profile +{ + public ProductsApplicationAutoMapperProfile() + { + CreateMap(); + } +} +```` +### Creating Example Products +In this section, we will create a few example products using the Swagger UI. In that way +... ## Creating the User Interface \ No newline at end of file