Use AutoMapper to map one object to another in ASP.NET Core

While developing ASP.NET Core web applications you often need to transfer
data residing in one object into another. You can accomplish this task manually
by setting properties of the target object with the values from the source
object. But wouldn't it be nice if this task can be automated? That's what the
AutoMapper library is about. In this article you learn to use AutoMapper in an
ASP.NET Core application.
Before you go into the details of AutoMapper, let's quickly understand how
AutoMapper can come handy with an example.
Consider the following user registration page developed in, say, ASP.NET Core
MVC.

As you can see, there are five form fields namely User Name, Password,
Confirm Password, Email, and Full Name.
You will typically grab the data entered by the end user in this page using
model binding. And hence you would create a view model class as shown below:
public class UserViewModel
{
public string UserName { get; set; }
public string Password { get; set; }
public string ConfirmPassword { get; set; }
public string Email { get; set; }
public string FullName { get; set; }
}
Now, in the UserViewModel class having Password and ConfirmPassword
properties is necessary because your validation system needs them in that way.
But the Entity Framework Core entity class won't have ConfirmPassword property
since that is not stored in the database table. Moreover, the entity class might
have additional properties such as UserId that are not captured by the view
model. So, the entity class will take this form:
public class AppUser
{
public int UserId { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public string FullName { get; set; }
}
By now it is clear to you that your data is captured into UserViewModel
object and you need to somehow transfer it into an AppUser object.
A straightforward approach is to manually create AppUser object and set its
properties with the respective values from UserViewModel.
public IActionResult Register
(UserViewModel model)
{
if (ModelState.IsValid)
{
AppUser user = new AppUser()
{
UserName = model.UserName,
Password = model.Password,
Email = model.Email,
FullName = model.FullName
};
db.Users.Add(user);
db.SaveChanges();
}
return View();
}
As you can see, the above code manually assigns values to AppUser object.
This is just a simple situation where object-to-object mapping is necessary.
In real world applications you will come across many such situations. That's
where AutoMapper can come handy.
Now let's see how AutoMapper can automate the object-object mapping in the
above example.
In order to use AutoMapper in ASP.NET Core web applications, you need to add
NuGet package for AutoMapper.Extensions.Microsoft.DependencyInjection. This is
shown below:

Next, you need to add this line to the ConfigureServices() to register
services required by AutoMapper with ASP.NET Core container.
public void ConfigureServices
(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddAutoMapper
(typeof(AutoMapperProfile).Assembly);
}
The AddAutoMapper() method registers the required services. It accepts an
Assembly (or multiple assemblies) containing the AutoMapper profiles (discussed
shortly).
Now, you need to create what is known as a AutoMapper profile. A profile is a
class that houses mapping information for objects. For example, you need to map
UserViewModel to AppUser and hence you need a profile class that specifies that
metadata information. The AutoMapperProfile class shown below shows how this
information is specified.
public class AutoMapperProfile : Profile
{
public AutoMapperProfile()
{
CreateMap<UserViewModel, AppUser>();
}
}
As you can see, the AutoMapperProfile class inherits from Profile base class.
The constructor calls the CreateMap() method that specifies a source and a
destination types to map. In this case UserViewModel is the source and AppUser
is the destination.
Once the AutoMapper profile is ready you can proceed to the Register() action
mentioned earlier and change the code as shown below:
private readonly IMapper mapper;
public HomeController(IMapper mapper)
{
this.mapper = mapper;
}
public IActionResult Register
(UserViewModel model)
{
if (ModelState.IsValid)
{
AppUser user = mapper.Map<AppUser>(model);
db.Users.Add(user);
db.SaveChanges();
}
return View();
}
The above code consists of two parts - the IMapper object injected into the
constructor and Register() action.
The IMapper object is injected by AutoMapper and is used for mapping the
objects as illustrated in the Register() action.
The Register() action uses Map() method of IMapper that specifies the
destination type and a source object. In this case UserViewModel object received
through model binding acts as the source and it is then mapped to AppUser
object.
A sample run of the application shows AppUser in quick watch window like
this:

So far so good.
In the example you just saw, the properties of source and destination object
were matching. What if they are different? Luckily, AutoMapper can handle such
situations with a bit of configuration.
Let's assume that UserViewModel class has a property named DisplayName
(instead of FullName) that needs to be mapped to FullName of AppUser. You can
accomplish this mapping as shown below:
public class AutoMapperProfile : Profile
{
public AutoMapperProfile()
{
CreateMap<UserViewModel, AppUser>()
.ForMember(destination => destination.FullName,
options => options.MapFrom(source => source.DisplayName));
}
}
Notice the code marked in bold letters, The ForMember() method specifies that
DisplayName property of source is mapped to the FullName property of
destination.
At times you need to map properties conditionally. For example, you might
want to map DisplayName to FullName only if it is different than UserName. You
can perform such conditional mapping as shown below:
public class AutoMapperProfile : Profile
{
public AutoMapperProfile()
{
CreateMap<UserViewModel, AppUser>()
.ForMember(destination => destination.FullName,
options => options.MapFrom(source => source.DisplayName))
.ForMember(destination => destination.FullName,
options => options.Condition(source => source.DisplayName
!= source.UserName));
}
}
Notice the code shown in bold letters. It uses Condition() method to specify
a mapping condition. A sample run of the application when UserName and
DisplayName are identical results in this:

As you can see FullName contains a null value because DisplayName and
UserName both were set to User1.
The AutoMapper provides many such features. You can read more about them
here.
That's it for now! Keep coding!!