November 27, 2016 AutoMapper, Opinion
November 27, 2016 AutoMapper, Opinion
AutoMapper is a great little library every .NET project is using (well, lots of them). I used it for the first time in 2010 and wrote a blog post about it.
Since that time I observed few things:
CreateMap
and Map
are still there and work the same. At the same time performance, testability, exception handling, and feature richness got improved significantly. Last one, in my opinion, is not such a good thing as it leads to the next point.AfterMap
or in different kinds of resolvers would simply start containg crazy things. In worst of those cases actual business logic was written in resolvers.I have always been of an opinion:
Less Code – Less Bugs; Simple Code – Good Code.
Having seen this trend with the library, I would like to suggest simplifying its usage by limiting ourselves. Simply:
ForMember
method it may be the case for doing it manually (at least for the specific type) – it will be cleaner and less confusing.Profile
class and Mapper.Initialize
method. If you still want to have at least some abstraction to avoid referencing AutoMapper everywhere make it simple.Here is how I’m using AutoMapper these days:
Somewhere in CommonAssembly a very-very simple abstraction (optional):
Somewhere in BusinessLogicAssembly and any other where you want to define mappings (can be split in as many profiles as needed):
Somewhere in startup code in BootstrappingAssembly (Global.asax
etc):
And here is the usage:
That’s it. I do not understand why some simple things are made complex.
There is also another advantage of keeping it minimalistic – maintainability. I’m working on a relatively new project that was created from a company’s template, as a result it had older version of AutoMapper abstracted. To upgrade it and keep all old interfaces would mean some work as abstraction used some of the APIs that did change. Instead I threw away all of these abstractions and upgraded the lib. Next time upgrading there simply will be way less code to worry about.
Please let me know if you share the same opinion.
Markdown | Result |
---|---|
*text* | text |
**text** | text |
***text*** | text |
`code` | code |
~~~ more code ~~~~ |
more code |
[Link](https://www.example.com) | Link |
* Listitem |
|
> Quote | Quote |
I think just the same. It’s very easy to get a lot of mess with AutoMapper and putting limits on its usage helps a lot.
There is a problem. For me, in great AutoMapper exists problem with just some required mappings. If multilanguage user interface application requires typical ability to change UI language dynamically, there is lack of corresponding solutions in AutoMapper – i.e. no parameter to select which one of source properties (i.e. from set of table columns) to map to destination property. The things are going even worse for us, when such flexibility is also typically required for related database tables. For such sub-mappings, such as 1 to many relation (collection of texts) or many to 1 relation (i.e. dictionary description) similar selection is required or close one if exact do not exists. There is also problem when the mapping requires many such dynamic selections at ones, i.e. UI interface have user selectable translation functionality (many parameters for mapping and sub-mappings?). Because all of that, many partial, strange, or nasty “solutions” for such problems exist in ours projects by years.
Tadeusz, as you said, AutoMapper cannot fit all of the scenarios and that is OK, as every application is different. This is why I think it doesn’t make sense to use AutoMapper for what it is not meant. If application requires some special mappings why not treat it as your business logic and test is separately. That’s at least what I think about this.
**Tadeusz**, I am not sure what you need but AutoMapper can (partially) do that. If you ask an author of AutoMapper, he will suggest you to use resolvers as they were specifically designed for such cases.
Yes, they make testing horrible since it is hard to test every resolver on its own. But do you really need to test each resolver separately? Most probably not.
`If application requires some special mappings why not treat it as your business logic and test is separately`
Makes sense. But since mapping logic is actually a “business logic”, then why would you split it? Then every developer should remember that for some cases he has to call Mapper.Map(…) and for others MyCustomMappingHelper.Map(…).
On the other hand, if your mappings for some entities are really super complex (which sometime is the case), then AutoMapper isn’t suitable for you from the beginning.
Less abstraction is often more, don’t abstract the most popular modules like Json.Net or IoC Containers (Autofac)…
The chance you want to remove a popular container for is very low. Its popular because it fits most if not all use cases and probably is also very performant. There is little chance, that you will find a Container that fits you better.
Still if you do in many cases you control your interfaces and implementations anyway and you can and will change all of them to fit the new library, so there was no use in abstraction anyway.
Michael, I completely agree with you. Most of very popular IoC, Logging and other common frameworks are very similar between each other. Changing from one framework to another is relatively easy, and I think it is even easier if you have less abstraction in place as there is chance that “abstraction” is actually tuned to one framework of choice. As you said: “so there was no use in abstraction anyway.”
Good advice! I really like the simple extension method approach.
Thank you, Paul. This extension makes mapping look very sleek and concise.
I totally agree with the general idea of mapping simple entities but unfortunately life isn’t all about mapping simple entities.
The problem of AutoMapper is not that you can add complex mapping logic (otherwise, ask yourself why would resolvers be implemented on the first place and not dropped for so long? The author made so many breaking changes in the past (latest version is a very good example) but never removed resolvers?). The problem is that it does not transparently expose this logic.
There is absolutely no difference between a resolver and your custom helper class, that decides whether or not to map PropertyA if another three properties are NULL, except one small thing: you can easily find your helper class and step into any method while debugging.
And with AutoMapper 5 it becomes even more tricky to navigate through mappings (however this version simplifies another very important thing, which I find more important than code navigation).
BTW, if you have a usecase “Use AutoMapper only for simple mapping” then AutoMapper is definitely a wrong choice. Use EmitMapper or TinyMapper (I personally used only the first one). Both of them are doing really great job at mapping your entities as fast as possible and _not_ having even half of the AutoMapper features. In fact, they are so dead simple that there is literary no way to add complex logic.
Volodymyr, thank you for your comments.
>> “except one small thing: you can easily find your helper class and step into any method while debugging.”
I think this is a great point. Plus your stack traces will be much nicer, and in general your code will be more readable.
>> ““Use AutoMapper only for simple mapping” then AutoMapper is definitely a wrong choice. Use EmitMapper or TinyMapper (I personally used only the first one)”
Maybe. I haven’t tried these two so I cannot comment on these libraries. Anyway I would still have a bit more faith in AutoMapper even for simple mappings as it is very mature, maintained, and tested in battles.
`I think this is a great point. Plus your stack traces will be much nicer, and in general your code will be more readable.`
I don’t consider stack traces as a huge issue. R# and Visual Studio make navigation easy at any time :)
I would say without AutoMapper your code is more “browsable”. Though there is a simple way of making code “browsable” with AutoMapper :) but unfortunately then you can’t use Mapper.Map(…) and extension methods like you propose.
`Anyway I would still have a bit more faith in AutoMapper even for simple mappings as it is very mature, maintained, and tested in battles.`
Also pretty often with every version update, if you use more advanced features than property-to-property mapping, you get very weird bugs. For example, once mapping context is passed and once not :) And don’t forget about breaking changes that are sometimes not announced! :D
Of course, nobody can stop you from using AutoMapper for property-to-ptoperty mapping only… but using it all the time exceptionally for this purpose is like buying a Ferrari and using it like a huge skateboard :D
That would be a hell of a skateboard!
Excellent advice
I agree with Volodymyr Usarskyy. The main point is that AutoMapper mapping suggest their own way to configure mapping, that is not type safe, so standart tools – Visual Studio, ReShaper, etc. can’t navigate and refactor this mapping. So for me this solution like list Dictionary – very universal, but create too many problems, and I not recoment it;
Automapper is poor solution for most project and cases, just because it suggest group Convert statements in one place, but It’s a kind of antipattern – conver is weak abstraction; Convert between Entity1 and Entity2 always absolutely has to relation with convert between Entity3 and Entity4, we have no reason group it; C# suggest standart syntax for convertion – static explicit\explicit method, that must be in Entity1 or Entity2, so compiler or developer can find it, and I believe that is only right way.
>Somewhere in startup code in BootstrappingAssembly (Global.asax etc):
>Mapper.Initialize(config =>
…
But when you write unit-tests (another composition root) you will have to repeat exactly the same code as in your Global.asax file, is not it? Looks like code smell for me. You will not have the same problem with manual mappers.