Browse Source

Merge pull request #23650 from abpframework/EngincanV/revise-docs

Revise all tutorials (and other docs) for Mapperly
pull/23656/head
Ma Liming 9 months ago
committed by GitHub
parent
commit
35904e185d
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 49
      docs/en/framework/architecture/domain-driven-design/application-services.md
  2. 11
      docs/en/framework/infrastructure/entity-cache.md
  3. 5
      docs/en/modules/docs.md
  4. 2
      docs/en/others/why-abp-platform.md
  5. 9
      docs/en/release-info/migration-guides/pro/openiddict-microservice.md
  6. 2
      docs/en/solution-templates/guide.md
  7. 47
      docs/en/tutorials/book-store/part-01.md
  8. 46
      docs/en/tutorials/book-store/part-03.md
  9. 14
      docs/en/tutorials/book-store/part-08.md
  10. 74
      docs/en/tutorials/book-store/part-09.md
  11. 47
      docs/en/tutorials/book-store/part-10.md
  12. 17
      docs/en/tutorials/microservice/part-05.md
  13. 22
      docs/en/tutorials/microservice/part-06.md
  14. 22
      docs/en/tutorials/modular-crm/part-03.md
  15. 20
      docs/en/tutorials/modular-crm/part-05.md
  16. 20
      docs/en/tutorials/modular-crm/part-06.md

49
docs/en/framework/architecture/domain-driven-design/application-services.md

@ -134,7 +134,7 @@ The `CreateAsync` method above manually creates a `Book` entity from given `Crea
However, in many cases, it's very practical to use **auto object mapping** to set properties of an object from a similar object. ABP provides an [object to object mapping](../../infrastructure/object-to-object-mapping.md) infrastructure to make this even easier.
Object to object mapping provides abstractions and it is implemented by the [AutoMapper](https://automapper.org/) library by default.
Object to object mapping provides abstractions and it is implemented by the [Mapperly](https://mapperly.riok.app/) library by default.
Let's create another method to get a book. First, define the method in the `IBookAppService` interface:
@ -162,36 +162,32 @@ public class BookDto
}
````
AutoMapper requires to create a mapping [profile class](https://docs.automapper.org/en/stable/Configuration.html#profile-instances). Example:
[Mapperly](https://mapperly.riok.app/) requires to create a mapping class that implements the `MapperBase<Book, BookDto>` class with the `[Mapper]` attribute as follows:
````csharp
public class MyProfile : Profile
```csharp
[Mapper]
public partial class BookToBookDtoMapper : MapperBase<Book, BookDto>
{
public MyProfile()
{
CreateMap<Book, BookDto>();
}
public override partial BookDto Map(Book source);
public override partial void Map(Book source, BookDto destination);
}
````
```
You should then register profiles using the `AbpAutoMapperOptions`:
Then, if your application uses multiple mapping providers, you should add the following configuration to your module's `ConfigureServices` method to decide which mapping provider to use:
````csharp
[DependsOn(typeof(AbpAutoMapperModule))]
[DependsOn(typeof(AbpMapperlyModule))]
public class MyModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpAutoMapperOptions>(options =>
{
//Add all mappings defined in the assembly of the MyModule class
options.AddMaps<MyModule>();
});
context.Services.AddMapperlyObjectMapper<MyModule>();
}
}
````
`AddMaps` registers all profile classes defined in the assembly of the given class, typically your module class. It also registers for the [attribute mapping](https://docs.automapper.org/en/stable/Attribute-mapping.html).
With this configuration, your module will use [Mapperly](https://mapperly.riok.app/) as the default mapping provider and you don't need to register mapping classes manually.
Then you can implement the `GetAsync` method as shown below:
@ -291,16 +287,21 @@ public class CreateUpdateBookDto
}
````
[Profile](https://docs.automapper.org/en/stable/Configuration.html#profile-instances) class of DTO class.
Define the mapping classes for [Mapperly](https://mapperly.riok.app/) as follows:
```csharp
public class MyProfile : Profile
[Mapper]
public partial class BookToBookDtoMapper : MapperBase<Book, BookDto>
{
public MyProfile()
{
CreateMap<Book, BookDto>();
CreateMap<CreateUpdateBookDto, Book>();
}
public override partial BookDto Map(Book source);
public override partial void Map(Book source, BookDto destination);
}
[Mapper]
public partial class CreateUpdateBookDtoToBookMapper : MapperBase<CreateUpdateBookDto, Book>
{
public override partial Book Map(CreateUpdateBookDto source);
public override partial void Map(CreateUpdateBookDto source, Book destination);
}
```

11
docs/en/framework/infrastructure/entity-cache.md

@ -88,6 +88,17 @@ public class MyMapperProfile : Profile
}
```
If you are using [Mapperly](https://mapperly.riok.app/), you can create a new mapping class that implements the `MapperBase<Product, ProductDto>` class with the `[Mapper]` attribute as follows:
```csharp
[Mapper]
public partial class ProductToProductDtoMapper : MapperBase<Product, ProductDto>
{
public override partial ProductDto Map(Product source);
public override partial void Map(Product source, ProductDto destination);
}
```
Now, you can inject the `IEntityCache<ProductDto, Guid>` service wherever you want:
```csharp

5
docs/en/modules/docs.md

@ -148,11 +148,6 @@ An ABP module must declare `[DependsOn]` attribute if it has a dependency upon a
{
options.DefinitionProviders.Add<MyProjectPermissionDefinitionProvider>();
});
Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<MyProjectApplicationAutoMapperProfile>();
});
}
}
```

2
docs/en/others/why-abp-platform.md

@ -169,7 +169,7 @@ The learning curve is much lower than not using the ABP. That may sound surprisi
ABP creates a full stack, production-ready, working solution for you in seconds. Many of the real-life problems are already solved and many fine tune configurations are already applied for the ASP.NET Core and the other used libraries. If you start from scratch, you will experience and learn all these details yourself to truly implement your solution.
ABP uses the industry standard frameworks, libraries and systems you already know (or need to learn to build a real-world product) like Angular, Blazor, MAUI, EF Core, AutoMapper, OpenIddict, Bootstrap, Redis, SignalR... etc. So, all your knowledge is directly re-usable with the ABP. ABP even simplifies using these libraries and systems and solves the integration problems. If you don't know these tools now, learning them will be easier within the ABP.
ABP uses the industry standard frameworks, libraries and systems you already know (or need to learn to build a real-world product) like Angular, Blazor, MAUI, EF Core, AutoMapper (switched to Mapperly due to licensing concerns), OpenIddict, Bootstrap, Redis, SignalR... etc. So, all your knowledge is directly re-usable with the ABP. ABP even simplifies using these libraries and systems and solves the integration problems. If you don't know these tools now, learning them will be easier within the ABP.
ABP provides an excellent infrastructure to apply DDD principles and other best practices. It provides a lot of sweet abstractions and automation to reduce the repeating code. However, it doesn't force you to use or apply all these. A common mistake is to see that ABP has a lot of features, and it is hard to learn all of them. Having a lot of features is an advantage when you come to the point that you need them. However, you don't need to know a feature until you need it, and you can continue with the development approach you are used to. You can still write code as you are used to as if ABP doesn't provide all these benefits. Learning the ABP infrastructure is progressive. You will love it whenever you learn a new feature but can continue developing without knowing its existence.

9
docs/en/release-info/migration-guides/pro/openiddict-microservice.md

@ -472,17 +472,12 @@ In `appsettings.json` replace **IdentityServer** section with **OpenIddict** and
typeof(AbpOpenIddictProWebModule),
```
- In **IdentityServiceWebModule.cs** add object mapping configurations:
- In **IdentityServiceWebModule.cs** add object mapping configurations for [Mapperly](https://mapperly.riok.app/) (if you are using an another mapping providers, see the [Object to Object Mapping](../../../framework/infrastructure/object-to-object-mapping.md) documentation):
```csharp
context.Services.AddAutoMapperObjectMapper<IdentityServiceWebModule>();
Configure<AbpAutoMapperOptions>(options =>
{
options.AddMaps<IdentityServiceWebModule>(validate: true);
});
context.Services.AddMapperlyObjectMapper<IdentityServiceWebModule>();
```
### Shared Hosting Module
- In **MyApplicationSharedHostingModule** replace the **database configuration**:

2
docs/en/solution-templates/guide.md

@ -27,7 +27,7 @@ Besides the overall solution structure, the internals of each project in a solut
### Library Integrations & Configurations
When you use ABP startup solution templates to create a new solution, some **fundamental library installations** ([Serilog](https://serilog.net/), [Autofac](https://autofac.org/), [AutoMapper](https://automapper.org/), [Swagger](https://swagger.io/), [HealthCheck](https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks) and others..) and their fine-tuned configurations are already prepared for you. Also, required **[ABP packages](https://abp.io/packages)** are just installed based on your preferences and configured for **development and production environments**.
When you use ABP startup solution templates to create a new solution, some **fundamental library installations** ([Serilog](https://serilog.net/), [Autofac](https://autofac.org/), [Mapperly](https://mapperly.riok.app/), [Swagger](https://swagger.io/), [HealthCheck](https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks) and others..) and their fine-tuned configurations are already prepared for you. Also, required **[ABP packages](https://abp.io/packages)** are just installed based on your preferences and configured for **development and production environments**.
### Development Ready

47
docs/en/tutorials/book-store/part-01.md

@ -291,22 +291,17 @@ public class BookDto : AuditedEntityDto<Guid>
* The `BookDto` is used to transfer the book data to the presentation layer in order to show the book information on the UI.
* The `BookDto` is derived from the `AuditedEntityDto<Guid>` which has audit properties just like the `Book` entity defined above.
It will be needed to map the `Book` entities to the `BookDto` objects while returning books to the presentation layer. [AutoMapper](https://automapper.org) library can automate this conversion when you define the proper mapping. The startup template comes with AutoMapper pre-configured. So, you can just define the mapping in the `BookStoreApplicationAutoMapperProfile` class in the `Acme.BookStore.Application` project:
It will be needed to map the `Book` entities to the `BookDto` objects while returning books to the presentation layer. [Mapperly](https://mapperly.riok.app/) library can automate this conversion when you define the proper mapping. The startup template comes with Mapperly pre-configured. So, you can just define the mapping in the `BookStoreApplicationMappers` class in the `Acme.BookStore.Application` project:
````csharp
using Acme.BookStore.Books;
using AutoMapper;
namespace Acme.BookStore;
public class BookStoreApplicationAutoMapperProfile : Profile
```csharp
[Mapper]
public partial class BookToBookDtoMapper : MapperBase<Book, BookDto>
{
public BookStoreApplicationAutoMapperProfile()
{
CreateMap<Book, BookDto>();
}
public override partial BookDto Map(Book source);
public override partial void Map(Book source, BookDto destination);
}
````
```
> See the [object to object mapping](../../framework/infrastructure/object-to-object-mapping.md) document for details.
@ -343,21 +338,23 @@ public class CreateUpdateBookDto
As done to the `BookDto` above, we should define the mapping from the `CreateUpdateBookDto` object to the `Book` entity. The final class will be as shown below:
````csharp
using Acme.BookStore.Books;
using AutoMapper;
```csharp
[Mapper]
public partial class BookToBookDtoMapper : MapperBase<Book, BookDto>
{
public override partial BookDto Map(Book source);
namespace Acme.BookStore;
public override partial void Map(Book source, BookDto destination);
}
public class BookStoreApplicationAutoMapperProfile : Profile
[Mapper]
public partial class CreateUpdateBookDtoToBookMapper : MapperBase<CreateUpdateBookDto, Book>
{
public BookStoreApplicationAutoMapperProfile()
{
CreateMap<Book, BookDto>();
CreateMap<CreateUpdateBookDto, Book>();
}
public override partial Book Map(CreateUpdateBookDto source);
public override partial void Map(CreateUpdateBookDto source, Book destination);
}
````
```
### IBookAppService
@ -416,7 +413,7 @@ public class BookAppService :
* `BookAppService` is derived from `CrudAppService<...>` which implements all the CRUD (create, read, update, delete) methods defined by the `ICrudAppService`.
* `BookAppService` injects `IRepository<Book, Guid>` which is the default repository for the `Book` entity. ABP automatically creates default repositories for each aggregate root (or entity). See the [repository document](../../framework/architecture/domain-driven-design/repositories.md).
* `BookAppService` uses `IObjectMapper` service ([see](../../framework/infrastructure/object-to-object-mapping.md)) to map the `Book` objects to the `BookDto` objects and `CreateUpdateBookDto` objects to the `Book` objects. The Startup template uses the [AutoMapper](http://automapper.org/) library as the object mapping provider. We have defined the mappings before, so it will work as expected.
* `BookAppService` uses `IObjectMapper` service ([see](../../framework/infrastructure/object-to-object-mapping.md)) to map the `Book` objects to the `BookDto` objects and `CreateUpdateBookDto` objects to the `Book` objects. The Startup template uses the [Mapperly](https://mapperly.riok.app/) library as the object mapping provider. We have defined the mappings before, so it will work as expected.
## Auto API Controllers

46
docs/en/tutorials/book-store/part-03.md

@ -298,23 +298,17 @@ public class EditModalModel : BookStorePageModel
### Mapping from BookDto to CreateUpdateBookDto
To be able to map the `BookDto` to `CreateUpdateBookDto`, configure a new mapping. To do this, open the `BookStoreWebAutoMapperProfile.cs` file in the `Acme.BookStore.Web` project and change it as shown below:
To be able to map the `BookDto` to `CreateUpdateBookDto`, configure a new mapping. To do this, open the `BookStoreWebMappers.cs` file in the `Acme.BookStore.Web` project and change it as shown below:
````csharp
using AutoMapper;
namespace Acme.BookStore.Web;
public class BookStoreWebAutoMapperProfile : Profile
```csharp
[Mapper]
public partial class BookDtoToCreateUpdateBookDtoMapper : MapperBase<BookDto, CreateUpdateBookDto>
{
public BookStoreWebAutoMapperProfile()
{
CreateMap<BookDto, CreateUpdateBookDto>();
}
}
````
public override partial CreateUpdateBookDto Map(BookDto source);
* We have just added `CreateMap<BookDto, CreateUpdateBookDto>();` to define this mapping.
public override partial void Map(BookDto source, CreateUpdateBookDto destination);
}
```
> Notice that we do the mapping definition in the web layer as a best practice since it is only needed in this layer.
@ -1288,28 +1282,26 @@ We can now define a modal to edit the book. Add the following code to the end of
</Modal>
````
### AutoMapper Configuration
### Mapperly Configuration
The base `AbpCrudPageBase` uses the [object to object mapping](../../framework/infrastructure/object-to-object-mapping.md) system to convert an incoming `BookDto` object to a `CreateUpdateBookDto` object. So, we need to define the mapping.
Open the `BookStoreBlazorAutoMapperProfile` inside the {{ if UI == "BlazorServer" }}`Acme.BookStore.Blazor` {{ else if UI == "MAUIBlazor" }}`Acme.BookStore.MauiBlazor` {{ else }}`Acme.BookStore.Blazor.Client`{{ end }} project and change the content as the following:
Open the `BookStoreBlazorMappers` inside the {{ if UI == "BlazorServer" }}`Acme.BookStore.Blazor` {{ else if UI == "MAUIBlazor" }}`Acme.BookStore.MauiBlazor` {{ else }}`Acme.BookStore.Blazor.Client`{{ end }} project and change the content as the following:
````csharp
using Acme.BookStore.Books;
using AutoMapper;
```csharp
using Riok.Mapperly.Abstractions;
using Volo.Abp.Mapperly;
{{ if UI == "BlazorServer" }}namespace Acme.BookStore.Blazor; {{ else if UI == "MAUIBlazor" }}namespace Acme.BookStore.MauiBlazor; {{ else }}namespace Acme.BookStore.Blazor.Client;{{ end }}
public class BookStoreBlazorAutoMapperProfile : Profile
[Mapper]
public partial class BookDtoToCreateUpdateBookDtoMapper : MapperBase<BookDto, CreateUpdateBookDto>
{
public BookStoreBlazorAutoMapperProfile()
{
CreateMap<BookDto, CreateUpdateBookDto>();
}
}
````
public override partial CreateUpdateBookDto Map(BookDto source);
* We've just added the `CreateMap<BookDto, CreateUpdateBookDto>();` line to define the mapping.
public override partial void Map(BookDto source, CreateUpdateBookDto destination);
}
```
### Test the Editing Modal

14
docs/en/tutorials/book-store/part-08.md

@ -193,7 +193,7 @@ public async Task<AuthorDto> GetAsync(Guid id)
}
````
This method simply gets the `Author` entity by its `Id`, converts to the `AuthorDto` using the [object to object mapper](../../framework/infrastructure/object-to-object-mapping.md). This requires to configure the AutoMapper, which will be explained later.
This method simply gets the `Author` entity by its `Id`, converts to the `AuthorDto` using the [object to object mapper](../../framework/infrastructure/object-to-object-mapping.md). This requires to configure the Mapperly, which will be explained later.
### GetListAsync
@ -350,12 +350,18 @@ Finally, add the following entries to the `Localization/BookStore/en.json` insid
## Object to Object Mapping
`AuthorAppService` is using the `ObjectMapper` to convert the `Author` objects to `AuthorDto` objects. So, we need to define this mapping in the AutoMapper configuration.
`AuthorAppService` is using the `ObjectMapper` to convert the `Author` objects to `AuthorDto` objects. So, we need to define this mapping in the Mapperly configuration.
Open the `BookStoreApplicationAutoMapperProfile` class inside the `Acme.BookStore.Application` project and add the following line to the constructor:
Open the `BookStoreApplicationMappers` class inside the `Acme.BookStore.Application` project and define the following mapping class:
````csharp
CreateMap<Author, AuthorDto>();
[Mapper]
public partial class AuthorToAuthorDtoMapper : MapperBase<Author, AuthorDto>
{
public override partial AuthorDto Map(Author source);
public override partial void Map(Author source, AuthorDto destination);
}
````
## Data Seeder

74
docs/en/tutorials/book-store/part-09.md

@ -335,27 +335,16 @@ The main reason of this decision was to show you how to use a different model cl
* Added `[DataType(DataType.Date)]` attribute to the `BirthDate` which shows a date picker on the UI for this property.
* Added `[TextArea]` attribute to the `ShortBio` which shows a multi-line text area instead of a standard textbox.
In this way, you can specialize the view model class based on your UI requirements without touching to the DTO. As a result of this decision, we have used `ObjectMapper` to map `CreateAuthorViewModel` to `CreateAuthorDto`. To be able to do that, you need to add a new mapping code to the `BookStoreWebAutoMapperProfile` constructor:
In this way, you can specialize the view model class based on your UI requirements without touching to the DTO. As a result of this decision, we have used `ObjectMapper` to map `CreateAuthorViewModel` to `CreateAuthorDto`. To be able to do that, you need to define a new mapping configuration in the `BookStoreWebMappers` class:
````csharp
using Acme.BookStore.Authors; // ADDED NAMESPACE IMPORT
using Acme.BookStore.Books;
using AutoMapper;
namespace Acme.BookStore.Web;
public class BookStoreWebAutoMapperProfile : Profile
```csharp
[Mapper]
public partial class CreateAuthorViewModelToCreateAuthorDtoMapper : MapperBase<Pages.Authors.CreateModalModel.CreateAuthorViewModel, CreateAuthorDto>
{
public BookStoreWebAutoMapperProfile()
{
CreateMap<BookDto, CreateUpdateBookDto>();
// ADD a NEW MAPPING
CreateMap<Pages.Authors.CreateModalModel.CreateAuthorViewModel,
CreateAuthorDto>();
}
public override partial CreateAuthorDto Map(Pages.Authors.CreateModalModel.CreateAuthorViewModel source);
public override partial void Map(Pages.Authors.CreateModalModel.CreateAuthorViewModel source, CreateAuthorDto destination);
}
````
```
"New author" button will work as expected and open a new model when you run the application again:
@ -456,29 +445,22 @@ This class is similar to the `CreateModal.cshtml.cs` while there are some main d
* Uses the `IAuthorAppService.GetAsync(...)` method to get the editing author from the application layer.
* `EditAuthorViewModel` has an additional `Id` property which is marked with the `[HiddenInput]` attribute that creates a hidden input for this property.
This class requires to add two object mapping declarations to the `BookStoreWebAutoMapperProfile` class:
This class requires to add two object mapping declarations, so open the `BookStoreWebMappers` class and add the following mappings:
```csharp
using Acme.BookStore.Authors;
using Acme.BookStore.Books;
using AutoMapper;
namespace Acme.BookStore.Web;
public class BookStoreWebAutoMapperProfile : Profile
[Mapper]
public partial class AuthorDtoToEditAuthorViewModelMapper : MapperBase<AuthorDto, EditAuthorViewModel>
{
public BookStoreWebAutoMapperProfile()
{
CreateMap<BookDto, CreateUpdateBookDto>();
public override partial EditAuthorViewModel Map(AuthorDto source);
CreateMap<Pages.Authors.CreateModalModel.CreateAuthorViewModel,
CreateAuthorDto>();
public override partial void Map(AuthorDto source, EditAuthorViewModel destination);
}
// ADD THESE NEW MAPPINGS
CreateMap<AuthorDto, Pages.Authors.EditModalModel.EditAuthorViewModel>();
CreateMap<Pages.Authors.EditModalModel.EditAuthorViewModel,
UpdateAuthorDto>();
}
[Mapper]
public partial class EditAuthorViewModelToUpdateAuthorDtoMapper : MapperBase<Pages.Authors.EditModalModel.EditAuthorViewModel, UpdateAuthorDto>
{
public override partial UpdateAuthorDto Map(Pages.Authors.EditModalModel.EditAuthorViewModel source);
public override partial void Map(Pages.Authors.EditModalModel.EditAuthorViewModel source, UpdateAuthorDto destination);
}
```
@ -1220,13 +1202,23 @@ This class typically defines the properties and methods used by the `Authors.raz
`Authors` class uses the `IObjectMapper` in the `OpenEditAuthorModal` method. So, we need to define this mapping.
Open the `BookStoreBlazorAutoMapperProfile.cs` in the {{ if UI == "BlazorServer" }}`Acme.BookStore.Blazor`{{ else if UI == "MAUIBlazor" }}`Acme.BookStore.MauiBlazor`{{ else }}`Acme.BookStore.Blazor.Client`{{ end }} project and add the following mapping code in the constructor:
Open the `BookStoreBlazorMappers.cs` in the {{ if UI == "BlazorServer" }}`Acme.BookStore.Blazor`{{ else if UI == "MAUIBlazor" }}`Acme.BookStore.MauiBlazor`{{ else }}`Acme.BookStore.Blazor.Client`{{ end }} project and add the following mappings in the class:
````csharp
CreateMap<AuthorDto, UpdateAuthorDto>();
````
```csharp
using Riok.Mapperly.Abstractions;
using Volo.Abp.Mapperly;
using Acme.BookStore.Authors;
//...
[Mapper]
public partial class AuthorDtoToUpdateAuthorDtoMapper : MapperBase<AuthorDto, UpdateAuthorDto>
{
public override partial UpdateAuthorDto Map(AuthorDto source);
You will need to declare a `using Acme.BookStore.Authors;` statement to the beginning of the file.
public override partial void Map(AuthorDto source, UpdateAuthorDto destination);
}
```
### Add to the Main Menu

47
docs/en/tutorials/book-store/part-10.md

@ -578,11 +578,17 @@ Let's see the changes we've done:
### Object to Object Mapping Configuration
Introduced the `AuthorLookupDto` class and used object mapping inside the `GetAuthorLookupAsync` method. So, we need to add a new mapping definition inside the `BookStoreApplicationAutoMapperProfile.cs` file of the `Acme.BookStore.Application` project:
Introduced the `AuthorLookupDto` class and used object mapping inside the `GetAuthorLookupAsync` method. So, we need to add a new mapping definition inside the `BookStoreApplicationMappers.cs` file of the `Acme.BookStore.Application` project:
````csharp
CreateMap<Author, AuthorLookupDto>();
````
```csharp
[Mapper]
public partial class AuthorToAuthorLookupDtoMapper : MapperBase<Author, AuthorLookupDto>
{
public override partial AuthorLookupDto Map(Author source);
public override partial void Map(Author source, AuthorLookupDto destination);
}
```
## Unit Tests
@ -898,12 +904,37 @@ These changes require a small change in the `EditModal.cshtml`. Remove the `<abp
### Object to Object Mapping Configuration
The changes above requires to define some object to object mappings. Open the `BookStoreWebAutoMapperProfile.cs` in the `Acme.BookStore.Web` project and add the following mapping definitions inside the constructor:
The changes above requires to define some object to object mappings. Open the `BookStoreWebMappers.cs` in the `Acme.BookStore.Web` project and create the following mapping definitions:
```csharp
CreateMap<Pages.Books.CreateModalModel.CreateBookViewModel, CreateUpdateBookDto>();
CreateMap<BookDto, Pages.Books.EditModalModel.EditBookViewModel>();
CreateMap<Pages.Books.EditModalModel.EditBookViewModel, CreateUpdateBookDto>();
using Riok.Mapperly.Abstractions;
using Volo.Abp.Mapperly;
//...
[Mapper]
public partial class CreateBookViewModelToCreateUpdateBookDtoMapper : MapperBase<Pages.Books.CreateModalModel.CreateBookViewModel, CreateUpdateBookDto>
{
public override partial CreateUpdateBookDto Map(Pages.Books.CreateModalModel.CreateBookViewModel source);
public override partial void Map(Pages.Books.CreateModalModel.CreateBookViewModel source, CreateUpdateBookDto destination);
}
[Mapper]
public partial class BookDtoToEditBookViewModelMapper : MapperBase<BookDto, Pages.Books.EditModalModel.EditBookViewModel>
{
public override partial Pages.Books.EditModalModel.EditBookViewModel Map(BookDto source);
public override partial void Map(BookDto source, Pages.Books.EditModalModel.EditBookViewModel destination);
}
[Mapper]
public partial class EditBookViewModelToCreateUpdateBookDtoMapper : MapperBase<Pages.Books.EditModalModel.EditBookViewModel, CreateUpdateBookDto>
{
public override partial CreateUpdateBookDto Map(Pages.Books.EditModalModel.EditBookViewModel source);
public override partial void Map(Pages.Books.EditModalModel.EditBookViewModel source, CreateUpdateBookDto destination);
}
```
You can run the application and try to create a new book or update an existing book. You will see a drop down list on the create/update form to select the author of the book:

17
docs/en/tutorials/microservice/part-05.md

@ -255,21 +255,20 @@ public class OrderAppService : ApplicationService, IOrderAppService
In this code snippet, we inject the `IRepository<Order, Guid>` into the `OrderAppService` class. We use this repository to interact with the `Order` entity. The `GetListAsync` method retrieves a list of orders from the database and maps them to the `OrderDto` class. The `CreateAsync` method creates a new order entity and inserts it into the database.
Afterward, we need to configure the *AutoMapper* object to map the `Order` entity to the `OrderDto` class. Open the `OrderingServiceApplicationAutoMapperProfile` class in the `CloudCrm.OrderingService` project, located in the `ObjectMapping` folder, and add the following code:
Afterward, we need to configure the *Mapperly* object to map the `Order` entity to the `OrderDto` class. Open the `OrderingServiceApplicationMappers` class in the `CloudCrm.OrderingService` project, located in the `ObjectMapping` folder, and add the following code:
```csharp
using AutoMapper;
using CloudCrm.OrderingService.Entities;
using CloudCrm.OrderingService.Services;
using Riok.Mapperly.Abstractions;
using Volo.Abp.Mapperly;
namespace CloudCrm.OrderingService.ObjectMapping;
public class OrderingServiceApplicationAutoMapperProfile : Profile
[Mapper]
public partial class OrderingServiceApplicationMappers : MapperBase<Order, OrderDto>
{
public OrderingServiceApplicationAutoMapperProfile()
{
CreateMap<Order, OrderDto>();
}
public override partial OrderDto Map(Order source);
public override partial void Map(Order source, OrderDto destination);
}
```

22
docs/en/tutorials/microservice/part-06.md

@ -216,25 +216,25 @@ public class OrderDto
}
```
Lastly, open the `OrderingServiceApplicationAutoMapperProfile` class (the `OrderingServiceApplicationAutoMapperProfile.cs` file under the `ObjectMapping` folder of the `CloudCrm.OrderingService` project of the `CloudCrm.OrderingService` .NET solution) and ignore the `ProductName` property in the mapping configuration:
Lastly, open the `OrderingServiceApplicationMappers` class (the `OrderingServiceApplicationMappers.cs` file under the `ObjectMapping` folder of the `CloudCrm.OrderingService` project of the `CloudCrm.OrderingService` .NET solution) and ignore the `ProductName` property in the mapping configuration:
```csharp
using AutoMapper;
using CloudCrm.OrderingService.Entities;
using CloudCrm.OrderingService.Services;
using Volo.Abp.AutoMapper;
using Riok.Mapperly.Abstractions;
using Volo.Abp.Mapperly;
namespace CloudCrm.OrderingService.ObjectMapping;
public class OrderingServiceApplicationAutoMapperProfile : Profile
[Mapper]
public partial class OrderingServiceApplicationMappers : MapperBase<Order, OrderDto>
{
public OrderingServiceApplicationAutoMapperProfile()
{
CreateMap<Order, OrderDto>()
.Ignore(x => x.ProductName); // New line
}
[MapperIgnoreTarget(nameof(OrderDto.ProductName))]
public override partial OrderDto Map(Order source);
[MapperIgnoreTarget(nameof(OrderDto.ProductName))]
public override partial void Map(Order source, OrderDto destination);
}
```
Let's explain the changes we made:
- We added a new property named `ProductName` to the `OrderDto` class. This property will hold the product name.

22
docs/en/tutorials/modular-crm/part-03.md

@ -323,23 +323,17 @@ Notice that `ProductAppService` class implements the `IProductAppService` and al
#### Object Mapping
`ProductAppService.GetListAsync` method uses the `ObjectMapper` service to convert `Product` entities to `ProductDto` objects. The mapping should be configured. Open the `CatalogAutoMapperProfile` class in the `ModularCrm.Catalog` project and change it to the following code block:
`ProductAppService.GetListAsync` method uses the `ObjectMapper` service to convert `Product` entities to `ProductDto` objects. The mapping should be configured. So, create a new mapping class in the `ModularCrm.Catalog` project that implements the `MapperBase<Product, ProductDto>` class with the `[Mapper]` attribute as follows:
````csharp
using AutoMapper;
namespace ModularCrm.Catalog;
public class CatalogAutoMapperProfile : Profile
```csharp
[Mapper]
public partial class ProductToProductDtoMapper : MapperBase<Product, ProductDto>
{
public CatalogAutoMapperProfile()
{
CreateMap<Product, ProductDto>();
}
}
````
public override partial ProductDto Map(Product source);
We've added the `CreateMap<Product, ProductDto>();` line to define the mapping.
public override partial void Map(Product source, ProductDto destination);
}
```
### Exposing Application Services as HTTP API Controllers

20
docs/en/tutorials/modular-crm/part-05.md

@ -283,21 +283,17 @@ The new files under the `ModularCrm.Ordering.Contracts` project should be like t
### Implementing the Application Service
First we configure the *AutoMapper* to map the `Order` entity to the `OrderDto` object, because we will need it later. Open the `OrderingAutoMapperProfile` under the `ModularCrm.Ordering` project:
First, create a new mapping class (under the `ModularCrm.Ordering` project) that implements the `MapperBase<Order, OrderDto>` class with the `[Mapper]` attribute to map `Order` entities to `OrderDto` objects as follows, because we will need it later:
````csharp
using AutoMapper;
namespace ModularCrm.Ordering;
public class OrderingAutoMapperProfile : Profile
```csharp
[Mapper]
public partial class OrderToOrderDtoMapper : MapperBase<Order, OrderDto>
{
public OrderingAutoMapperProfile()
{
CreateMap<Order, OrderDto>();
}
public override partial OrderDto Map(Order source);
public override partial void Map(Order source, OrderDto destination);
}
````
```
Now, you can implement the `IOrderAppService` interface. Create an `OrderAppService` class under the `ModularCrm.Ordering` project:

20
docs/en/tutorials/modular-crm/part-06.md

@ -217,21 +217,17 @@ public class OrderDto
}
````
Lastly, open the `OrderingAutoMapperProfile` class (the `OrderingAutoMapperProfile.cs` file under the `Services` folder of the `ModularCrm.Ordering` project of the `ModularCrm.Ordering` .NET solution) and ignore the `ProductName` property in the mapping configuration:
Lastly, open the `OrderingApplicationMappers` class (the `OrderingApplicationMappers.cs` file under the `Services` folder of the `ModularCrm.Ordering` project of the `ModularCrm.Ordering` .NET solution) and add the following mapping class:
````csharp
using AutoMapper;
using Volo.Abp.AutoMapper;
namespace ModularCrm.Ordering;
public class OrderingApplicationAutoMapperProfile : Profile
[Mapper]
public partial class OrderToOrderDtoMapper : MapperBase<Order, OrderDto>
{
public OrderingApplicationAutoMapperProfile()
{
CreateMap<Order, OrderDto>()
.Ignore(x => x.ProductName); // New line
}
[MapperIgnoreTarget(nameof(OrderDto.ProductName))]
public override partial OrderDto Map(Order source);
[MapperIgnoreTarget(nameof(OrderDto.ProductName))]
public override partial void Map(Order source, OrderDto destination);
}
````

Loading…
Cancel
Save