@ -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
`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);
@ -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:
@ -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.
@ -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):
@ -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**.