AutoMapper.Mapper.CreateMap : Dynamically creating maps will be removed in version 5.0

AutoMapper from version 4.2 the static method CreateMap is obsolete and will be removed at version 5. It’s been years that people are configuring their mapping with this static method. Most people have divided their mapping into multiple classes across their model (domain) classes. While this can be a big task for huge solution, in most case the migration is simple. This article shows how to migrate from the static CreateMap method into a custom static variable that will handle all configurations. While the new patterns is great to be injected, it doesn’t mean that you should change your whole solution now to go in that direction.

First of all, if you had a custom interface or base class for the classes that define your mapping you should use instead AutoMapper.Profile. Having your class using this interface lets you override a method called Configure. You can from that base class call base.CreateMap. Since you access the CreateMap method, not statically, and with the same signature, the migration is easy. Here is an example.

public class OverallMapping: Profile
{
	protected override void Configure()
	{
		base.CreateMap<HealthOverall, HealthOverallViewModel>();
	}
}

The last step is to have all profiles loaded into your static variable. The easiest way is to use reflection to loops through all classes and to get all classes that inherit from Profile. The method that use the reflection is called once in your Global.asax.cs during the application start. Since it’s called once, the reflection call is not problematic on performance of your web application.

public static class MappingConfiguration
{
	public static void CreateMapping()
	{
		var profiles = (from type in typeof(MappingConfiguration).Assembly.GetTypes()
						where typeof(Profile).IsAssignableFrom(type) && !type.IsAbstract && type.GetConstructor(Type.EmptyTypes) != null
						select type).Select(d => (Profile)Activator.CreateInstance(d))
									 .ToArray();

		var config = new MapperConfiguration(cfg =>
		{
			foreach (var profile in profiles)
			{
				cfg.AddProfile(profile);
			}
		});
		MapperFacade.MapperConfiguration = config.CreateMapper();
	}
}

public static class Mapper{
	public static IMapper MapperConfiguration;
}

The static class and static property that hold all mapping is what you need to use in your application to map anything.

var viewModel = MapperFacade.MapperConfiguration.Map<HealthOverall, HealthOverallViewModel>(model);

That’s it! Pretty straight forward. What is time consuming is to change mapping configuration but this is still limited if your application already had a good division about how to define the mapping.

How to copy attribute from one property to another

Earlier, I showed how to transfer attribute form model class to view model class with AutoMapper and Asp.Net MVC. This work fine but what if the view model class has a custom property that manipulate even further the data and that you would like to display on screen a display attribute from another property of the model class? The solution we had in the previous post transferred the display attribute from the model to the view model’s property by using AutoMapper to map the DisplayAttribute with the corresponding From and To property. But how can we extends this logic to be able to pass this attribute to another property of the view model class? This is what we will resolve in this article. The following image illustratre the desired result. We want the property B from the view model to use the p roperty A display attribute that come from the model property A.
ModelToViewModel

The first part, is already been done in the AutoMap code from the previous article. This is the code that map the attribute from the model to view model. The next step is to specify in the view model that we need to transfer from one property’s attribute to the other property. This require to create a new attribute where we can specify from which property we want to get the attributes.

public class CopyAttributesFrom : Attribute
{
    public string PropertyName { get; set; }
}

Then, we need to use it in the view model class. This class is limited to one property: the name of the property to take attributes. The mapping is than 1-1, nothing fancy. Let’s see an example. The following code is having two property. The first one get from the model some attributes and the second one want to get the attribute from the first property (which also has once mapped the ones from the model).

public TimeSpan? MinimumHoldingTime { get; set; }

[CopyAttributesFrom(PropertyName = "MinimumHoldingTime")]
public int? MinimumHoldingTimeMinutes {
    get { 
        return  this.MinimumHoldingTime.HasValue ? Convert.ToInt32(this.MinimumHoldingTime.Value.TotalMinutes) : (int?)null;
    }
}

Why don’t we map directly into AutoMapper the logic? Because the code we are using to transfer attributes from the model to viewmodel works with DestinationProperty and not an expression. Having logic in the ForMember method of AutoMapper uses an expression. This force us to map the value and in a second step to have the property desired with the data manipulated.

In the code to map with AutoMapper model attributes to view model, we had a custom DataAnnotationsModelMetadataProvider. This one need to be adjusted to add attributes from our custom a CopyAttributesFrom attribute.

public class MappedDataAnnotationsModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
    private readonly IConfigurationProvider mapper;

    public MappedDataAnnotationsModelMetadataProvider(IConfigurationProvider mapper)
    {
        this.mapper = mapper;
    }

    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
    {
        //Copy attributes from the model and to the view model
        var mappedAttributes = containerType == null ? attributes.ToList() : mapper.GetMappedAttributes(containerType, propertyName, attributes).ToList();

        //Map CopyAttributes attributes
        foreach (var attributeCopy in attributes.Where(d => d.GetType() == typeof (CopyAttributesFrom)).Cast<CopyAttributesFrom>())
        {
            var propertyFromTheMappedModelOfTheCopiedProperty = mapper.GetMappedAttributes(containerType, attributeCopy.PropertyName, attributes).ToList();
            mappedAttributes.AddRange(propertyFromTheMappedModelOfTheCopiedProperty);
        }
        var modelMetadata = base.CreateMetadata(mappedAttributes, containerType, modelAccessor, modelType, propertyName);
        return modelMetadata;
    }
}

The foreach is where everything happen. We verify that the property we map is marked with our copy attribute; if yes, we go in AutoMapper to get from the model the attributes. We must go back to the model and not directly copy the attributes from the specified viewmodel’s attribute because this one may not already been transferred from the model — we do not control the order that CreateMetaData is invoked. Nevertheless, this is not a problem, we take the view model property name, and instead of binding the attribute to the property specified we bind them to the property we are creating the metadata.

If you are not using this whole AutoMapper model/view model mapping, you can get a similar result by using the .Net framework. Here is how.

var sourceProperty = containerType.GetProperty(attributeCopy.PropertyName);
var allAttributeFromSpecifiedProperty = sourceProperty.GetCustomAttributes(true);
foreach (object attr in allAttributeFromSpecifiedProperty)
{
    mappedAttributes.Add(attr as Attribute);
}

Nonetheless, this solution has a pitfall which is the way we specify the property to copy the attributes — this one is hardcoded. Refactoring of this class is harder and the string may be unsynchronize with a property rename. However, since we localize the copy to the class itself and not beyond this boundary, the instability is restrained. This is a limitation of the actual .Net framework which does not allow to use expression inside an attribute.

How to AutoMap Asp.Net Attribute from Model to ViewModel

If you are using DisplayAttribute and DataAnnotation Attribute with an architecture that use Model and ViewModel, by default, you have to duplicate those attributes. The problem is that you cannot keep all display attribute on the view model only because you want to have you exception to have the display name into it. You also want to have the data annotation on your model because they add validation into the model, not into a class designed for rendering, the view model. That say, Display Attribute and Data Annotation are quite useful in Asp.net because they are using for Label and for client-side validation. So, we need them in both place. The best place is to have the attribute on the Model classes. Mostly because the model classes are the heart of the system where logic of your system live.

With that in mind, we need when transferring the values from the model classes into the view model classes transfer the attributes too. This require some works to change some Asp.Net behaviors and also do some work with AutoMapper to maps more than just the specified properties but also attributes for those specified properties. All code discussed in this article is open sourced in this Git Repository : https://github.com/MrDesjardins/AutoMapperAttributesMapping.

The first change is on Asp.Net MVC. We need to define a new DataAnnotationsModelMetadataProvider. The goal of this class is to create a new provider to handle attributes. So every times MVC will access the attributes on the view model, it will call this method. We will access AutoMapper and get from the attributes from the model. As you can notice, we pass inside the constructor a IConfigurationProvider that allow you to pass AutoMapper configuration.

internal class MappedDataAnnotationsModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
	private readonly IConfigurationProvider mapper;

	public MappedDataAnnotationsModelMetadataProvider(IConfigurationProvider mapper)
	{
		this.mapper = mapper;
	}

	protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
	{
		var mappedAttributes = containerType == null ? attributes : mapper.GetMappedAttributes(containerType, propertyName, attributes).ToArray();
		var modelMetadata = base.CreateMetadata(mappedAttributes, containerType, modelAccessor, modelType, propertyName);
		return modelMetadata;
	}
}

This class must be instantiated during the startup of you web project. Ideally in the Global.asax. I created a class to have a public access which can be called from the global.asax.

public class ModelMetadataProviderConfig
{
    public static void RegisterModelMetadataProvider()
    {
        ModelMetadataProviders.Current = new MappedDataAnnotationsModelMetadataProvider(Mapper.Engine.ConfigurationProvider);
    }
}

The big piece of code is with AutoMapper. The DataAnnotationsModelMetaDataProvider calls the GetMappedAttributes from AutoMapper. This is a custom method that do the mapping for attributes. This method is pretty big and do a lot of looping. The first one is looping all the registered mapping. We need to get from all mapper where we are going to map to the destination one. Since we are using the meta data from the type used inside the view, which is the View Model class, we need to search through the list of mapping for the destination type. This can lead to several mapping, this is why we have a second loop that search for the property name. We make sure that we search only for mapped type, not those ignored. The last loop can be customized for your need. I decided to map attribute that are of type ValidationAttribute and DisplayAttribute.

public static IEnumerable<Attribute> GetMappedAttributes(this IConfigurationProvider mapper,
	Type viewModelType,
	string viewModelPropertyName,
	IEnumerable<Attribute> viewModelPropertyAttributes)
{
	if (viewModelType == null)
		throw new ArgumentNullException("viewModelType");

	//For all automapper configurations about the view model we are working with
	foreach (var typeMap in mapper.GetAllTypeMaps()
		.Where(i => i.DestinationType == viewModelType))
	{
		//Get the properties from the model we found from automapper
		var propertyMaps = typeMap.GetPropertyMaps()
			.Where(propertyMap => !propertyMap.IsIgnored() && propertyMap.SourceMember != null)
			.Where(propertyMap => propertyMap.DestinationProperty.Name == viewModelPropertyName);

		foreach (var propertyMap in propertyMaps)
		{
			//Only get the attribute from the model if the view model does not define it
			foreach (Attribute attribute in propertyMap.SourceMember.GetCustomAttributes(typeof(ValidationAttribute), true))
			{
				if (!viewModelPropertyAttributes.Any(i => i.GetType().IsInstanceOfType(attribute)
														  || attribute.GetType().IsInstanceOfType(i)))
					yield return attribute;
			}
			//Only get the attribute from the model if the view model does not define it
			foreach (Attribute attribute in propertyMap.SourceMember.GetCustomAttributes(typeof(DisplayAttribute), true))
			{
				if (!viewModelPropertyAttributes.Any(i => i.GetType() == attribute.GetType()))
					yield return attribute;
			}

		}
	}

	//Add all view model attribute
	if (viewModelPropertyAttributes != null)
	{
		foreach (var attribute in viewModelPropertyAttributes)
		{
			yield return attribute;
		}
	}
}

This method returns a list of attributes that are then set to the ViewModel object with the call to the base.CreateMetaData method. To see the result, you can add a display attribute on the model and see what is happening when you use the Html helper for label.

public class UserModel
{
    public int Id { get; set; }

    [Display(Name = "First Name Here")]
    public string FirstName { get; set; }
    public string LastName { get; set; }
}
public class UserViewModel
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

The .csHtml:

<div class="row">
    <div class="col-md-6">
        @Html.LabelFor(d => d.FirstName)
        @Html.TextBoxFor(d => d.FirstName)
    </div>
    <div class="col-md-6">
        @Html.LabelFor(d => d.LastName)
        @Html.TextBoxFor(d => d.LastName)
    </div>
</div>

Display
This example shows one label that has the Display attribute, this is the FirstName, and one that does not have it, this is the LastName. For the complete code and example, go to GitHub.

AutoMapper and constructor with parameters

In some use case you are forced to have classes that has constructor with parameters. This is more rare if you are using Entity Framework (EF) because it requires to have parameterless constructor. However, if the scenario occurs, remember that AutoMapper does not have this constrain. In fact, you can have a private parameterless constructor for Entity Framework (EF) and force the use of a public constructor with parameters when using in your code.

First of all, during the mapping configuration, you must use ConstructUsingServiceLocator method.

Mapper.CreateMap<ContestEditableViewModel, Model.Entities.Contest.Contest>()
      .ConstructUsingServiceLocator();

This instruct AutoMapper to check for the option ConstructServicesUsing method that can be provided during the mapping instruction.

Second, when you are using AutoMapper to map between classes, you must specify every parameters.

var model = AutoMapper.Mapper.Map<ContestEditableViewModel, Model.Entities.Contest.Contest>(viewModel
                , options=>options.ConstructServicesUsing(
                    t=>new Model.Entities.Contest.Contest(yourFirstParameter, yourSecondParameter, /*and so on*/)
                )
            );

This way, you can have classes that have parameters and control how to provided them values.

Using AutoMapper to Map Abstract Classes

AutoMapper lets you map from one class to another class your object. It works fine until you want to map from a class to an abstract class. The reason is that AutoMapper instantiates the desired class type and since an abstract class cannot be instantiate will crash.

//Mapping
Mapper.CreateMap<SelectorItem, OrderType>()
//Use the mapping
var model = AutoMapper.Mapper.Map<SelectorItem, OrderType>(viewModel);

The code create the map from SelectorItem that is a normal class and OrderType that is an abstract class. The use of this map will not work. To fix this problem the mapping configuration must be changed to specify to AutoMapper how to instantiate the OrderType class, the abstract class.

Mapper.CreateMap<SelectorItem, OrderType>()
      .ConstructUsing(OrderTypeCreator);

The mapping requires the use of ConstructUsing method that has two signatures.

IMappingExpression<TSource, TDestination> ConstructUsing(Func<TSource, TDestination> ctor);
IMappingExpression<TSource, TDestination> ConstructUsing(Func<ResolutionContext, TDestination> ctor);

The first one is easy to use. It takes a method that has the source which is the class we start with and return a destination class that is the abstract class.

private OrderType OrderTypeCreator(SelectorItem arg)
{
     return OrderType.GetFromId(arg.Id);
}

This example takes from the concrete class the ID and use a factory to return the correct concrete class that inherit form the abstract OrderType class.

This way, we have AutoMapper that can map to abstract Class without problem.

Automapper bind automatically property of property by concatenating property name

This title has a lot of properties, I know. Today, I’ll show you with a simple unit test that Automapper bind properties’ property automatically with their name. For example, a class that has a property called User that has by itself a property called FirstName and LastName, will auto-bind to MyMappedClass.UserFirstName and MyMappedClass.UserLastName.

[TestClass]
public class UnitTest1
{
	public class ClassA
	{
		public ClassA()
		{
			this.PropertyA = new ClassAB();
		}

		public ClassAB PropertyA { get; set; }
	}

	public class ClassAB
	{
		public int Id { get; set; }
		public string Suffixe { get; set; }
		public string NotTheSame { get; set; }
	}

	public class ClassB
	{
		public int PropertyAId { get; set; }
		public string PropertyASuffixe { get; set; }
		public string NotReallyTheSame { get; set; }
	}

	[TestMethod]
	public void TestMethod1()
	{
		var c = new ClassA();
		c.PropertyA.Id = 123;
		Mapper.CreateMap<ClassA, ClassB>();
		var mapped = Mapper.Map<ClassA, ClassB>(c);
		Assert.AreEqual(c.PropertyA.Id,mapped.PropertyAId);
		Assert.AreEqual(c.PropertyA.Suffixe,mapped.PropertyASuffixe);
		Assert.IsNull(mapped.NotReallyTheSame);
	}
}

AutoMapperSuccess

The code above show you this reality. The ClassA is mapped to ClassB. Class A doesn’t specify any Automapper configuration, just a single CreateMap without options. Nevertheless, Automapper is bright enough to bind Id and Suffixe from ClassA to ClassB. This is because the name of those properties are present in the mapped ClassB class with the concatenation of the two properties name.

Automapper Ignore vs UseDestinationValue, what is the difference?

Automapper gives you big leverage when it’s the time to transfer values from one object into another object. While most of the transfer is done automatically with AutoMapper, sometimes, specific values must not be transferred. Imagine the case for a destination class that has not the property or for a class that has do not want the value from the source but will compute the value in its constructor.

Automapper gives the property Ignore which tells the mapper to not take the value of a property from the source class. Ignore not only ignore the mapping for the property, but also ignore the mapping of all inner properties. It means that if the property is not a primitive type, but another class, that if you are using Ignore, this class properties won’t be mapped. So, A.B.C would be A.Null.

But, if you have a scenario that you must not map a property, but map all inner properties should remain then you should use UseDestinationValue. That will end to be A.B.C -> A.B.C (where B is from the destination class, not the source class, probably initialized in the destination’s constructor).

To conclude, Ignore method will not map any property, neither the inner properties of the property defined to be ignored. UseDestinationValue will not map the property. It keeps the existing value of the property but will map the value of this one. It’s the same with a collection. The reference of the collection stays the same while the object inside is mapped.

How to create a mapping to a primitive type with AutoMapper.

If you want to map one of your complex object to a primitive you cannot use the ForMember method of Automapper to do it. Instead, you have to use the ConvertUsing.

Here is a case of ComplexType which reprensent a boolean value.

	Mapper
	.CreateMap<ComplexType, bool>()
	.ConvertUsing(f=>f.ID);

	Mapper
	.CreateMap<bool, ComplexType>()
	.ConvertUsing(f => new ComplexType(f));

This is usefull if you have view models that represent primitive data and you want them to be represented into a view model object.

How to handle a null property with Automapper

AutoMapper is a library that you can find now at GitHub. It’s the same one that has been hosted on CodePlex previously. The purpose of the AutoMapper library is to allow you to transfert value from an object to another. This is usefull when you are working with DTO object or when you need to map properties between your model and view model.

In this article, I’ll show you how to handle a null property. This case occur if you have a source object that has a null property and you want to have in the destination a value. A simple example would be that you have a User class that can have a classe Address. If this one is null, you may want to have in the destination an empty string or a default string value.

public class UserSource
{
	public Address Address{get;set;}
}

public class UserDestination
{
	public string Address{get;set;}
}

First, the mapping require to have the indication of your action.

AutoMapper.Mapper.CreateMap<UserSource, UserDestination>()
					.ForMember(dest => dest.Address
					, opt => opt.NullSubstitute("Address not found")
					);

This indicate to map Address to Address (default behavior) but has the optional with NullSubstitute which let you specify an object to be used for the mapping if the source object is null. In the previous example, a string has been used but a default object could have been used without problem.

Here is how to call the mapper. The mapping is done without any other option than normal mapping.

var model = AutoMapper.Mapper.Map<UserSource, UserDestination>(user);
var models = AutoMapper.Mapper.Map<IEnumerable<UserSource>, IEnumerable<UserDestination>>(users);