Hands-On ASP.NET Core 3.1 : Learn MVC, Razor Pages, Web API, Entity Framework Core, and Blazor. Private online coaching for software developers. Click here to know more.

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!!


Bipin Joshi is an independent software consultant, trainer, author, yoga mentor, and meditation teacher. He has been programming, meditating, and teaching for 24+ years. He conducts instructor-led online training courses in ASP.NET family of technologies for individuals and small groups. He is a published author and has authored or co-authored books for Apress and Wrox press. Having embraced the Yoga way of life he also teaches Ajapa Yoga to interested individuals. To know more about him click here.

Get connected : Facebook  Twitter  LinkedIn  YouTube

Posted On : 03 February 2020


Tags : ASP.NET ASP.NET Core Data Access MVC C# Visual Studio


Subscribe to our newsletter

Get monthly email updates about new articles, tutorials, code samples, and how-tos getting added to our knowledge base.

  

Receive Weekly Updates