Anton Anton - 1 month ago 56
C# Question

How to use mapper.Map inside MapperConfiguration of AutoMapper?

I need to map an object to another one using AutoMapper. The tricky question is how can I access an instance of the mapper (instance of IMapper) inside of the mapping configuration or inside of a custom type converter?

The code below does not work, however it is an example of what I would like to achieve - please notice the

mapper.Map
calls and assume that mappings
Customer => CustomerDto
and
Customer => DetailedCustomerDto
are defined.

var config = new MapperConfiguration(
cfg => cfg.CreateMap<Order, OrderDto>()
.ForMember(dst => dst.Customer, src => src.ResolveUsing(o => {
return o.Type == 1
? mapper.Map<Customer, CustomerDto>(o.Customer)
: mapper.Map<Customer, DetailedCustomerDto>(o.Customer)
})
);


The client part is:

var mapper = config.CreateMapper();
var orderDto = mapper.Map<Order, OrderDto>(order);


The simplified version of objects I want to map is:

public class Order
{
public int Type { get; set; }
public Customer Customer { get; set; }
}

public class Customer
{
public long Id { get; set; }
public string Name { get; set; }
}

public class OrderDto
{
public CustomerDto Customer { get; set; }
}

public class CustomerDto
{
public long Id { get; set; }
}

public class DetailedCustomerDto : CustomerDto
{
public string Name { get; set; }
}


As you see from the codes above, based on the value of
Order.Type
, the mapper should map the property
Order.Customer
to different targets. As one target (
DetailedCustomerDto
) inherits from the other one (
CustomerDto
) it becomes a bit tricky.

Please notice that usage of the obsolete and deprecated static method Mapper.Map is NOT an option.

Evk Evk
Answer

As of AutoMapper 5.1.1

You can get to the mapper using another overload of ResolveUsing with four parameters, fourth of which is ResolutionContext (context.Mapper):

var config = new MapperConfiguration(
    cfg => {
        cfg.CreateMap<Customer, CustomerDto>();
        cfg.CreateMap<Customer, DetailedCustomerDto>();
        cfg.CreateMap<Order, OrderDto>()
             .ForMember(dst => dst.Customer, src => src.ResolveUsing((order, orderDto, i, context) => {
                return order.Type == 1
                ? context.Mapper.Map<Customer, CustomerDto>(order.Customer)
                : context.Mapper.Map<Customer, DetailedCustomerDto>(order.Customer);
        }));
 });

 var orderTypeOne = new Order();
 orderTypeOne.Type = 1;
 orderTypeOne.Customer = new Customer() {
    Id = 1
 };

 var dto = config.CreateMapper().Map<Order, OrderDto>(orderTypeOne);
 Debug.Assert(dto.Customer.GetType() == typeof (CustomerDto));

 var orderTypeTwo = new Order();
 orderTypeTwo.Type = 2;
 orderTypeTwo.Customer = new Customer() {
     Id = 1
 };
 dto = config.CreateMapper().Map<Order, OrderDto>(orderTypeTwo);
 Debug.Assert(dto.Customer.GetType() == typeof (DetailedCustomerDto));

Prior to AutoMapper 5.1.1

You can get to the mapper using another overload of ResolveUsing with two parameters, first of which is ResolutionResult (result.Context.Engine.Mapper):

var config = new MapperConfiguration(
    cfg => {
        cfg.CreateMap<Customer, CustomerDto>();
        cfg.CreateMap<Customer, DetailedCustomerDto>();
        cfg.CreateMap<Order, OrderDto>()
             .ForMember(dst => dst.Customer, src => src.ResolveUsing((result, order) => {
                return order.Type == 1
                ? result.Context.Engine.Mapper.Map<Customer, CustomerDto>(order.Customer)
                : result.Context.Engine.Mapper.Map<Customer, DetailedCustomerDto>(order.Customer);
        }));
 });

 var orderTypeOne = new Order();
 orderTypeOne.Type = 1;
 orderTypeOne.Customer = new Customer() {
    Id = 1
 };

 var dto = config.CreateMapper().Map<Order, OrderDto>(orderTypeOne);
 Debug.Assert(dto.Customer.GetType() == typeof (CustomerDto));

 var orderTypeTwo = new Order();
 orderTypeTwo.Type = 2;
 orderTypeTwo.Customer = new Customer() {
     Id = 1
 };
 dto = config.CreateMapper().Map<Order, OrderDto>(orderTypeTwo);
 Debug.Assert(dto.Customer.GetType() == typeof (DetailedCustomerDto));