In this document
Introduction
It's common to map a similar object to another object. It's also tedious and repetitive since generally both objects (classes) may have the same/similar properties mapped to each other. Imagine a typical application service method below:
public class UserAppService : ApplicationService
{
private readonly IRepository<User> _userRepository;
public UserAppService(IRepository<User> userRepository)
{
_userRepository = userRepository;
}
public void CreateUser(CreateUserInput input)
{
var user = new User
{
Name = input.Name,
Surname = input.Surname,
EmailAddress = input.EmailAddress,
Password = input.Password
};
_userRepository.Insert(user);
}
}
CreateUserInput is a simple DTO class and User is a simple entity. We manually created a User entity from the given input. The User entity will have more properties in a real-world application and manually creating it will become tedious and error-prone. We also have to change the mapping code when we want to add new properties to User and CreateUserInput.
We can use a library to automatically handle our mappings. AutoMapper is one of the best libraries for object to object mapping. ASP.NET Boilerplate defines an IObjectMapper interface to abstract it and then implements this interface using AutoMapper in the Abp.AutoMapper package.
IObjectMapper Interface
IObjectMapper is a simple abstraction that has Map methods to map an object to another. We can replace the above code with this, instead:
public class UserAppService : ApplicationService
{
private readonly IRepository<User> _userRepository;
private readonly IObjectMapper _objectMapper;
public UserAppService(IRepository<User> userRepository, IObjectMapper objectMapper)
{
_userRepository = userRepository;
_objectMapper = objectMapper;
}
public void CreateUser(CreateUserInput input)
{
var user = _objectMapper.Map<User>(input);
_userRepository.Insert(user);
}
}
Map is a simple method that gets the source object and creates a new destination object with the type declared as the generic parameter (User in this sample). The Map method has an overload to map an object to an existing object. Assume that we already have a User entity and want to update it's properties using an object:
public void UpdateUser(UpdateUserInput input)
{
var user = _userRepository.Get(input.Id);
_objectMapper.Map(input, user);
}
AutoMapper Integration
The Abp.AutoMapper NuGet package (module) implements the IObjectMapper and provides additional features.
Installation
First, install the Abp.AutoMapper NuGet package to your project:
Install-Package Abp.AutoMapper
Then add a dependency for AbpAutoMapperModule to your module definition class:
[DependsOn(typeof(AbpAutoMapperModule))]
public class MyModule : AbpModule
{
...
}
You can then safely inject and use IObjectMapper in your code. You can also use AutoMapper's own API when you need it.
Creating Mappings
Before using the mapping, AutoMapper requires you to define mappings between classes (by default). You can see AutoMapper's own documentation for details on mapping. ASP.NET Boilerplate makes it a bit easier and modular.
Auto Mapping Attributes
Most of the time you may only want to directly (and conventionally) map classes. In this case, you can use the AutoMap, AutoMapFrom and AutoMapTo attributes. For instance, if we want to map the CreateUserInput class to the User class in the sample above, we can use the AutoMapTo attribute as shown below:
[AutoMapTo(typeof(User))]
public class CreateUserInput
{
public string Name { get; set; }
public string Surname { get; set; }
public string EmailAddress { get; set; }
public string Password { get; set; }
}
The AutoMap attribute maps two classes in both directions. But in this sample, we only need to map from CreateUserInput to User, so we used AutoMapTo.
Custom Mapping
Simple mapping may not be suitable in some cases. For instance, property names of two classes may be a little different or you may want to ignore some properties during the mappping. In such cases you should directly use AutoMapper's API to define the mapping. The Abp.AutoMapper package defines an API to make custom mapping more modular.
Assume that we want to ignore Password on mapping and the User has a slightly different named Email property. We can define the mapping as shown below:
[DependsOn(typeof(AbpAutoMapperModule))]
public class MyModule : AbpModule
{
public override void PreInitialize()
{
Configuration.Modules.AbpAutoMapper().Configurators.Add(config =>
{
config.CreateMap<CreateUserInput, User>()
.ForMember(u => u.Password, options => options.Ignore())
.ForMember(u => u.Email, options => options.MapFrom(input => input.EmailAddress));
});
}
}
AutoMapper has many more options and abilities for object to object mapping. See it's documentation for more info.
Pre Defined Mappings
LocalizableString -> string
The Abp.AutoMapper module defines a mapping to convert LocalizableString (or ILocalizableString) objects to string objects. It makes the conversion using ILocalizationManager, so localizable properties are automatically localized during the mapping process of any class.
Injecting IMapper
You may need to directly use AutoMapper's IMapper object instead of IObjectMapper abstraction. In that case, just inject IMapper in your classes and use it. The Abp.AutoMapper package registers the IMapper with dependency injection as a singleton.