AutoMapper doesn’t actually save much time… and other reasons not to use it

I’m definitely a fan of keeping software architecture as simple and as minimal as possible… KISS, YAGNI etc. In line with this I try to keep use of third party tools to an absolute minimum and stick with out of the box stuff as much as possible.

One tool I’ve used in the past based on its popularity and proposed benefits is AutoMapper. It’s used to automatically assign values from one object to another based on conventions such as matching property names. It’s used quite a lot to map entity classes to viewModel/EditModel classes and despite its authors protestations is often used to map viewModel/EditModel classes back to entity classes too. Does AutoMapper save time?

AutoMapper doesn’t actually save much time

AutoMapper is supposed to save the time developers would spending typing out all the manual and so called tedious left-right assignments in code. I’ve used AutoMapper on three projects and each time so much configuration was required or so much confusion about why something wasn’t working as expected was experienced by the developers that after all was said and done it would have just been quicker to type the code out manually. And besides left-right assignment code is pretty much the easiest code any developer is ever going to have to write, everyone understands it (including the BAU team who did not write the app but who will support it) and it’s very rare to lose significant time on software projects because of the sheer volume of code we have to type. It’s always the research, whiteboarding, collaboration, brainstorming required to figure out what code to write, not actually writing it that costs the most time.

In the projects I worked on which used AutoMapper tasks which the team lost time on included debugging cryptic error messages, writing custom rules when something non trival is inevitably needed, explaining to junior developers how it all works/is supposed to work and funnily enough discussing the merits of using it or not. All these tasks added up to more than the time saved by not typing mappings manually so I wouldn’t consider including AutoMapper in a build again unless the system was very large and the vast majority of mappings could be done without custom mappers. Other reasons I’d choose manual mappings over AutoMapper include…

Run time errors as no compile time errors
Mappings are computed at runtime, so if your mapping object A to B and rename a property on one but not the other you won’t know until runtime. AssertConfigurationIsValid can however be called at startup or from a unit test to ensure you do indeed catch these issues at runtime.

No static analysis
Find all references won’t find references for many properties as they not explicitly used.

Long term support?
This isn’t specific to AutoMapper, but AutoMapper is mainly written by a talented guy called Jimmy Bogard. Although he has a bit of help, its still a pretty small project which may not be around or supported in a couple of years. Given that software in the industry I’m working in now (banking) often has a life time of 20 years this is a factor I needed to consider too, although again this is not specific to AM.

Recommendations for using AutoMapper

For me I no longer see the benefits of using it and I’d just rather not create a dependency on someone elses kit without it having validated benefits, but each to their own so if you intend on using it keep your life simple by:

Not using custom mappers as you end up writing almost as much code as you would to do things manually. Wrap standard Mapper.Map / source class -> destination code in an extension method (for example) and then do plain left-right assignment for anything that doesn’t map out of the box, this means your using less of the complex features of AutoMapper but still getting the majority of your properties mapped:

OrderDto dto = Mapper.Map<OrderDto>(order);
dto.CustomerFullName = order.FirstName + ‘ ‘ + order.LastName;

Call AssertConfigurationIsValid at startup when in development mode. You can’t get compile time errors but you can check for valid mappings immediately upon runtime. Keep an eye on how long this takes however.

Am guilty of doing this in the past myself but avoid using AutoMapper to go from ViewModels to entities as there is a lot of black box stuff going on which quite often doesn’t sit well with entity framework and causes unintended consequences such as triggering inserts rather than updates. Simply put your entities are too important to use AutoMapper on, do them manually…

FYI, not using AutoMapper is fine

Retrofiting in Automapper has no advantagesIn the not too distant past during some refactor time on an almost done project an external architect recommended to our team that we retrofit AutoMapper in after we had manually done all the left-right assignments without issue. Recommendation was based on the fact we were not using AutoMapper rather than on the need for a solution to a problem we were having (we were having none). There would have been absolutely no benefit only cost to using AutoMapper at that point. Point is with AutoMapper and other third party tools you should resist the urge to use them just because they are popular or the big books mention them, consider that everything has a cost and the choice to use something or not should depend on your project particulars not what is flavour of the month on StackOverflow or other developer hangouts online.

Automapper 4.2 IgnoreAllNonExisting – ignore missing properties

Given that Automapper 4.2 has marked the static API as obsolete we shouldn’t be using things like Mapper.GetAllTypes() etc. as they will be removed in version 5. A 4.2+ version of a popular extension method for ignoring properties which exist on the destination type but not on the source type is below:

public static IMappingExpression<TSource, TDestination> 
    IgnoreAllNonExisting<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
    foreach(var property in expression.TypeMap.GetUnmappedPropertyNames())
    {
        expression.ForMember(property, opt => opt.Ignore());
    }

    return expression;
}
 

Automapper 4.2 example

Automapper 4.2 has marked the static API as obsolete so things should be done slightly differently than before as the static API will be dropped completely in version 5. Creating maps without the static API in 4.2 is simple. Below is an automapper 4.2 example which creates two maps and uses one with a mapper.Map statement, where mapper is a call to an instance not a static API.

var config = new MapperConfiguration(cfg =>
{
 cfg.CreateMap<PlayerViewModel, PlayerDTO>()
 .ForMember(dst => dst.NickName, opt => opt.MapFrom(src => src.FanName))
 .ForMember(dst => dst.YearsOld, opt => opt.MapFrom(src => src.Age));
 
 cfg.CreateMap<TeamViewModel, TeamDTO>()
 .ForMember(dst => dst.TeamName, opt => opt.MapFrom(src => src.Name))
 .ForMember(dst => dst.CoachFullName, opt => opt.MapFrom(src =>   src.ManagerFullName));
});

config.AssertConfigurationIsValid();
var mapper = config.CreateMapper();
TeamDTO DTO = mapper.Map<TeamDTO>(TeamViewModel.getTeamViewModel());

The first block would go in global.asax or similar. The second block is used throughout your application to actually do the conversions from source to destination objects.

two way automapper mapping with child properties mapped too

Quite often in our development projects which use automapper we will not only want to convert an object A to an object B but also from B to A. Think of a scenario using ASP.Net Web API and MVC for example where the web API returns a customerDTO which is converted to a customerViewModel and used to display a strongly typed razor view. On post back of that view we are going to want to turn the viewModel (if it’s valid) back into a customerDTO for passing to the web API PUT /Customer method for updating.

Very limited automapper two way mapping support

Automapper has very basic support for two way mapping out of the box via the ReverseMap() method which will allow you to reverse a map in one line rather than two like below:

reverseMap

In the above scenario ReverseMap() makes things slightly cleaner but as the original A to B mapping is very simple we are really only saving a few characters. What however if A and B were not perfect mirrors of each other and we needed ForMember() overrides because the names from the two objects don’t map or we need to do anything other than simple assignment from source to destination? Unfortunately there isn’t anything that can help with this scenario as ReverseMap() doesn’t map these overrides so you need to manually do them. It would be nice for example if the first block below was equivalent to the second and third blocks combined as it would save a good bit of time.

automapper-not-eqiuvalent

Automapper 4.2 two way mapping support

Fortunately thanks to Automapper’s extension points and .net extension methods it’s not too difficult to rig up something a little more useful. I spent a couple of hours on the below extension method over the weekend.

mapping-create

Three important parts of the extension method (which is available to download below) which are highlighted above:

1. Reversing of the overall map and returning of IMappingExpression, just like built in ReverseMap() does.
2. Storing the old destination value (now the new source value) into correct new destination property for value types.
3. Setting reference types by casting from object (creating cast errors for lists at moment – to change)

I can then configure my original A->B mappings and call the new reverse map method in a manner similar to below:

configure-automapper

I’m getting the reverse map to correctly map back primitive properties which are of the same type whose names just don’t match. Instance properties with or without the same name between source and destination seem to be working too.

Note the highlights in yellow above, for mappings from reference to value types and for collections you still need explicit mapping. For example for the initial PlayerViewModel->PlayerDTO mapping I used ForMember to convert from int->string, but an exception was thrown when I tried to reverse it if AssertConfgurationIsValid() was being called. If I removed the AssertConfgurationIsValid() call the destination int was always 0. I think I will need to use a type convertor like the accepted answer on this stackoverflow page. At the moment if types are not both valueType or both referenceType I continue so don’t attempt the mapping.

Although collections with different names were mapping correctly and populating the destination property, the AssertConfigurationIsValid() function was throwing a non ‘missing property’ type exception as my code was causing a casting issue when going from object -> list which I’m looking into. Therefore I am just skipping the reverse rule for generic types for the moment and continuing to the next map. To recap… the reverse mapping for collections worked without an explicit ForMember map, but AssetConfigurationIsValid() failed. If you don’t use the AssetConfigurationIsValid() method you don’t need to explicitly set the reverse mapping for lists etc. (but remember to remove the IsGenericType skip clause I’ve got in the extension method first)

Download the full two way reverse map automapper code

As you can see it still needs a little bit of work… but definitely an improvement on what was there. Here is the full ReverseMapWithForMemberPreserved extension method code, including the viewModels, DTOs, mapping configurations etc. The viewModels and DTOs model football teams and players etc. and yes I am a Liverpool Football Club supporter.

You will see a version of the extension for both Automapper 4.2 and 4.1 and below. The new 4.2 version has dropped the static API so things needed to be done slightly different than before. Lots of things which were in 4.1 are now marked as obsolete in 4.2 which is the version I ran both the 4.1 and 4.2 approaches in. These obsolete methods will be deleted in 5.0 so it’s recommend to upgrade to 4.2+ as soon as you can.

Automapper thrives on convention over configuration

Hopefully you can use the above code as a start if you want to try and rig improved bi-directional mapping into automapper. In an ideal world it wouldn’t be needed however as I’d obviously recommend a convention over configuration approach where property names on source and destination classes match exactly or at least use some defined format which can possibly be mapped using ‘RecognizePrefix’. See ‘Recognizing pre/postfixes’ section on the automapper configuration wiki page on Github for an example of how this might work.

The more convention that’s used, the more value I feel is derived from automapper. If every property name differs between your source and destination classes then you’re going to have so many .ForMember() explicit mappings that it probably would make more sense to just use plain left right C# assignment to do the mapping.