Automapper – Use IoC for creating Destinations

Automapper by default creates new instances of destination using the default contructor. If you need to ask the IoC to create the new instance, it actually turns out to be pretty simple.
We will begin by setting up our Unity Container to register the IMapper.

var mapper = MappingProfile.InitializeAutoMapper(_unityContainer).CreateMapper();

_unityContainer.RegisterInstance<IMapper>(mapper);

As you can see, you are also initializing the Automapper with certain configurations. Let’s see what exactly it is. Following is the definition of MapperProfile.

public static class MappingProfile
{
public static MapperConfiguration InitializeAutoMapper(IUnityContainer container)
{
MapperConfiguration config = new MapperConfiguration(cfg =>
{
cfg.ConstructServicesUsing(type => container.Resolve(type));
cfg.AddProfile(new AssemblyProfile());
});
return config;
}
}

As you can observe, you are configuring the Automapper to Construct using the IUnityContainer. The following line does the magic for you as it uses the existing Container to create new instances (if registered with IoC) each time Automapper finds a particular type in destination.

cfg.ConstructServicesUsing(type => container.Resolve(type));

In the next blog post, we will investigate Automapper in bit more deeply. For now, please refere the sample code demonstrating the blog post at my Github

Mapping XML Using Automapper

Automapper comes handy when you have to deal with a lot of DTOs, making it very easy to map one type to another. But there are situations where you might need an extra hand.

Consider the following Type definitions.

public class SourceUser
{
public string Name {get;set;}
public int Age {get;set;}
public string Address {get;set;}
}

public class DestinationUser
{
public string UserName{get;set;}
public int Age{get;set;}
public Address Address{get;set;}
}
public class Address
{
public string City {get;set;}
public string State {get;set;}
public string Country {get;set;}
}

The Source.Address is a XML representation of Address. Your requirement is to configure Automapper to convert SourceUser to DestinationUser. Let’s define an example SourceUser first, so that our demonstration could be easier.

var sourceUser = new SourceUser
{
Name = "Anu Viswan",
Age = 35,
Address = "<Address><County>India</Country><State>Kerala</State><City>Cochin</City></Address>"
};

This is where ConstructUsing method of comes into place. The first step is define our custom Construction Method.

static DestinationUser ConstructAddress(SourceUser src)
{
XDocument xdoc = new XDocument();
xdoc = XDocument.Parse(src.Address);
var destinationUser = new DestinationUser
{
Address = new Address
{
Country = xdoc.Root.Element(nameof(Address.Country)).Value,
City = xdoc.Root.Element(nameof(Address.City)).Value,
State = xdoc.Root.Element(nameof(Address.State)).Value,
}
};

return destinationUser;
}

With our Construction Method ready, we now move on to configure Automapper.

Mapper.Initialize(cfg =>
cfg.CreateMap<SourceUser, DestinationUser>()
.ConstructUsing(x => ConstructAddress(x))
.ForMember(dest => dest.UserName, source => source.MapFrom(s => s.Name))
.ForMember(dest => dest.Age, source => source.MapFrom(s => s.Age))
.ForMember(dest=> dest.Address, source => source.Ignore()));

Do note that we have relied on Automapper for rest of Properties, which can be easily mapped. It is also important to instruct Automapper to Ignore the Address property in its routine parsing. That would give you the desired result and you can map the incompatible Types using the following.

var destinationUser = Mapper.Map<DestinationUser>(sourceUser);