An open source library used to map objects, AutoMapper’s Nuget package has been downloaded more than 21.5 million times and is usually one of the top 20 downloaded community Nuget package. It has a convention based auto mapping of properties with same name & type, from which it derives its name. It has a plethora of useful features & auto mapping may actually not be advisable, as covered below.
This is an attempt to lay out why I think AutoMapper is good & how best to use it.
For the first timers, following is a quick example of AutoMapper code.
As can be seen, the properties can be mapped using a simple syntax that allows evaluation of conditions. This is a small window of the capabilities that include the possibility of calling injected services and manipulating data before and after the mapping is done.
The author of AutoMapper generated it to tackle problems he faced daily, and is still using it, to my knowledge. Such dog fooding has lead to relevant software that’s evolved based on feedback and community input. It has moved away from its static API and use of reflection that it relied on heavily before.
It lends itself to putting the mappings creation in different classes (called Profiles, which are unit testable) as needed by the domain. These can be usually picked up the IOC container so any new Profile added to the project is auto included. In fact, the extension provided for .Net Core does that with one line of code.
The best way to use AutoMapper is to inject its mapping interface into the calling classes.
The biggest advantage of using it for me is the ability to allow the calling code to fully delegate the responsibility of mapping to AutoMapper, in all but exceptional cases. As such its invaluable tool in implementing the SOLID principles. As an example, a typical controller method using AutoMapper may be as below.
The above code clearly gives the flow of the method, abstracting away any irrelevant details that are not the responsibility of the controller. It is also easily unit testable by passing mocks, which don’t have to setup the models being passed around. This code and its tests will not need to change if the properties of the models or the way they’re mapped is altered.
Mappings created in AutoMapper are reused where needed without any extra configuration. Which means in the example below AutoMapper will look for mappings from AddressDto to Address class and OrderDto to Order class and use them. Of course there will be a detailed error at runtime if any of those are not found so please do call
AssertConfigurationIsValid() at the start of the application.
AutoMapper also allows using inheritance if both the source and destination classes inherit from another set of classes which have been mapped, as the
Include<> line does below. This can also be done in derived classes by calling
If all that is not enough AutoMapper also takes care of converting collections. Any collection can be converted to any other collection so long as the classes are mapped.
AutoMapper also has support for generics, which allows mapping a generic class to another one.
The above are reasons enough for me to utilise AutoMapper. Quite often issues arise if its not used in a way conducive to its capabilities, which I’ll try and highlight in the Dos & Donts below.
- Inject the mapping interface
IMappingEngine) to map the objects, instead of calling the static Mapper.
- Create the mappings in classes inheriting from AutoMapper’s
Profileclass, using it’s
CreateMapmethod in the constructor (in the latest version).
- Use the
AssertConfigurationIsValid()method on the mapper configuration after all the profiles have been added. It should also be used in the Profiles’ unit tests. This method raises an exception with detailed messages is any of the property of the destination class has not been mapped. Not perfect but still indispensable.
- Map each property individually even if the other property is of same name & type. This is very useful in the long run for maintainability & traceability of code.
- When mapping properties of an object order them alphabetically, it makes it easier to track things if the objects become bigger.
- Tell, don’t ask. The FullName mapping in the first example (or the last one) could be done as below as long as types from one layer don’t seep into another.
- Use custom value resolvers and custom type converters. If AutoMapper is setup properly, services can be injected into these to allow complex mappings. This will prevent partial mapping of classes in AutoMapper and then calling services to map the remaining properties in the calling method.
- Before and After Map actions can be used to tackle complex mappings that need setup or manipulation post mapping, which is not the concern of calling object.
- Don’t use the static API. Using
Mapper.Mapprevents injecting AutoMapper and that means all mappings will have to setup for unit tests that call AutoMapper, instead of mocking them out, which can be major burden as projects get larger.
- The convention based automatic mapping of same named properties should be avoided for better maintainability & easier tracking of properties.
- Avoid one line ignoring of the unmapped properties for objects you own, as shown below. This feature should only be used for large third party objects where we don’t care what may change. For the classes we own, the properties should be ignored individually for better tracking and maintenance.
- Avoid database calls directly from AutoMapper code, of which I’ve seen examples on the internet. AutoMapper should only call services, if needed to map objects.
- Personally, I avoid using Queryable extensions of AutoMapper which allow calling AutoMapper projections while querying the database using an ORM like Nhibernate or Entity Framework. Getting the objects from database & then mapping them explicitly is more maintainable IMHO.