joydip_kanjilal
Contributor

More advanced AutoMapper examples in .Net Core

how-to
Jul 15, 20197 mins
Development Libraries and FrameworksMicrosoft .NETSoftware Development

How to use profiles, reverse mapping, nested mapping, and other advanced operations of the open source object mapper AutoMapper

abstract data perspective composition
Credit: Thinkstock

AutoMapper is a convention-based, object-oriented mapper. An object-oriented mapper is one that transforms an input object into an output object of a different type. AutoMapper also can be used to map similar or dissimilar objects (i.e., objects having properties that may or may not be identical).

We examined the basic features of AutoMapper in a previous article. In this article we’ll explore some of the advanced features of AutoMapper.

Create an ASP.Net Core project in Visual Studio

First off, let’s create a new ASP.Net Core project in Visual Studio. Note that you can create any project, i.e., MVC or even a Console Application, to work with AutoMapper. If Visual Studio 2019 is installed in your system, follow the steps outlined below to create a new ASP.Net Core project.

  1. Launch the Visual Studio IDE.
  2. Click on “Create new project.”
  3. In the “Create new project” window, select “ASP.Net Core Web Application” from the list of templates displayed.
  4. Click Next. 
  5. In the “Configure your new project” window shown next, specify the name and location for the new project.
  6. Click Create. 
  7. In the “Create New ASP.Net Core Web Application” window shown next, select .Net Core as the runtime and ASP.Net Core 2.2 (or later) from the drop-down menu at the top.
  8. Select “Web Application” as the project template to create a new ASP.Net Core web application. 
  9. Ensure that the check boxes “Enable Docker Support” and “Configure for HTTPS” are unchecked as we won’t be using those features here.
  10. Ensure that Authentication is set to “No Authentication” as we won’t be using authentication either.
  11. Click Create. 

Now you should have a new ASP.Net Core project ready to go in Visual Studio. We’ll use this project in the subsequent sections of this article to illustrate a few advanced operations using AutoMapper.

Install AutoMapper

To start working with AutoMapper, you should install the necessary packages in your project. To do this, you can use the following commands at the NuGet Package Manager Console window:

Install-Package AutoMapper
Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection

Assuming the installation is successful, you are all set to use AutoMapper in your project.

Configure AutoMapper

Once AutoMapper has been successfully installed, you can configure it by calling the AddAutoMapper method on the IServiceCollection instance.

public void ConfigureServices(IServiceCollection services)
        {         
            services.AddMvc().SetCompatibilityVersion
            (CompatibilityVersion.Version_2_2);
            services.AddAutoMapper();
        }

Use profiles to specify mapping information in AutoMapper

You can organize your mapping collections using profiles. To create a profile, you need to create a class that extends the Profile class of the AutoMapper library. You can then add the necessary mapping configuration information to the constructor of the class you just created. The CreateMap method is used to create mapping between two types.

The following class shows how you can create a class named AuthorProfile by extending the Profile class and specifying mapping information.

public class AuthorProfile : Profile
{
     public AuthorProfile()
     {
         CreateMap<AuthorModel, AuthorDTO>();
     }
}

Use the ReverseMap() method in AutoMapper

Note that the example above is a one-way mapping. Similarly, suppose you have defined a one-way mapping using the CreateMap method as shown in the code snippet below.

AutoMapper.Mapper.CreateMap<Author, AuthorModel>();

You can now map an instance of the Author class to an AuthorModel as shown below.

var authorModel = AutoMapper.Mapper.Map<AuthorModel>(author);

Now suppose you would like to map the AuthorModel instance back to an Author instance. You might try using the following code.

var author = AutoMapper.Mapper.Map<Author>(authorModel);

However, note that this would throw a runtime exception. The exception occurs because the AutoMapper runtime lacks the knowledge needed to perform this mapping. One way to achieve this reverse mapping is by recreating the mapping from the scratch. A simpler and better way is by using the ReverseMap method off the CreateMap method, as shown in the code snippet below.

AutoMapper.Mapper.CreateMap<Author, AuthorModel>().ReverseMap();

Use the ForMember() and MapFrom() methods in AutoMapper

This next example will use the AuthorModel and AuthorDTO classes from my previous article on AutoMapper. You can refer to that article here.

The following code snippet illustrates how you can map objects of the AuthorModel and AuthorDTO classes.

var author = new AuthorModel();           
author.Id = 1;
author.FirstName = "Joydip";
author.LastName = "Kanjilal";
author.Address = "Hyderabad";
var authorDTO = _mapper.Map<AuthorDTO>(author);

Now suppose the property named Address has been changed to Address1 in the AuthorModel class.

public class AuthorModel
   {
       public int Id
       {
           get; set;
       }
       public string FirstName
       {
           get; set;
       }
       public string LastName
       {
           get; set;
       }
       public string Address1
       {
           get; set;
       }
   }

You can then update the mapping information in the AuthorProfile class as shown below.

public class AuthorProfile : Profile
    {
        public AuthorProfile()
        {
            CreateMap<AuthorModel, AuthorDTO>().ForMember
             (destination => destination.Address,
             map => map.MapFrom(source => source.Address1));          
        }
    }

Use NullSubstitute in AutoMapper

Suppose the Address field in the AuthorModel is null and you would like to have something like “No data” in lieu of a null value. Here’s where NullSubstitution comes into action. The following code snippet illustrates how it can be used to replace null values with “No data”.

AutoMapper.Mapper.CreateMap<AuthorModel, AuthorDTO>()
  .ForMember(destination => destination.Address, opt => opt.NullSubstitute("No data"));

Use before and after mapping in AutoMapper

Consider the following two classes.

public class OrderModel
  {
    public int Id { get; set; }
    public string ItemCode { get; set; }
    public int NumberOfItems { get; set; }
  }
public class OrderDTO
  {
    public int Id { get; set; }
    public string ItemCode { get; set; }
    public int NumberOfItems { get; set; }
  }

You can take advantage of the BeforeMap() method to perform some calculation or initialize a data member in the source or destination instance. The following code snippet illustrates how this can be achieved.

Mapper.Initialize(cfg => {
  cfg.CreateMap()
    .BeforeMap((src, dest) => src.NumberOfItems = 0)
});

The AfterMap() method can be used to execute operations on the destination object after a mapping has been done. Here’s how you can use the AfterMap() method on the destination instance.

 public OrderDTO MapAuthor(IMapper mapper, OrderDTO orderDTO)
        {
            return mapper.Map<OrderModel, OrderDTO>(orderDTO, opt =>
            {
                opt.AfterMap((src, dest) =>
                {
                    dest.NumberOfItems =
                    _orderService.GetTotalItems(src);
               });
            });
        }

Use nested mapping in AutoMapper

AutoMapper can be used to map nested objects as well. Consider the following domain classes.

public class Order
    {
        public string OrderNumber { get; set; }
        public IEnumerable<OrderItem> OrderItems { get; set; }
    }
public class OrderItem
    {
        public string ItemName { get; set; }
        public decimal ItemPrice { get; set; }
        public int ItemQuantity { get; set; }
    }

Consider the following classes that represent data transfer objects.

public class OrderDto
    {
        public string OrderNumber { get; set; }
        public IEnumerable<OrderItemDto> OrderItems { get; set; }
    }
public class OrderItemDto
    {
        public string ItemName { get; set; }
        public decimal ItemPrice { get; set; }
        public int ItemQuantity { get; set; }
    }

You can use the following code to establish a mapping.

var orders = _repository.GetOrders();
Mapper.CreateMap<Order, OrderDto>();
Mapper.CreateMap<OrderItem, OrderItemDto>();
var model = Mapper.Map<IEnumerable<Order>, IEnumerable<OrderDto>>(orders);

AutoMapper enables you to map objects with minimal configuration. You can even map objects having different data structures by using a custom resolver. The custom resolver can generate an exchange object that has the same structure as the destination object so that the AutoMapper runtime can map the types at runtime.

joydip_kanjilal
Contributor

Joydip Kanjilal is a Microsoft Most Valuable Professional (MVP) in ASP.NET, as well as a speaker and the author of several books and articles. He received the prestigious MVP award for 2007, 2008, 2009, 2010, 2011, and 2012.

He has more than 20 years of experience in IT, with more than 16 years in Microsoft .Net and related technologies. He has been selected as MSDN Featured Developer of the Fortnight (MSDN) and as Community Credit Winner several times.

He is the author of eight books and more than 500 articles. Many of his articles have been featured at Microsoft’s Official Site on ASP.Net.

He was a speaker at the Spark IT 2010 event and at the Dr. Dobb’s Conference 2014 in Bangalore. He has also worked as a judge for the Jolt Awards at Dr. Dobb's Journal. He is a regular speaker at the SSWUG Virtual Conference, which is held twice each year.

More from this author