AutoMapper

Do not misuse or over abstract AutoMapper

November 27, 2016 AutoMapper, Opinion 14 comments

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:

  • Almost every project I worked on, that needed some kind of object mapping, was using this lib. In rare cases there was some pet library or manual mapping in place.
  • Almost every project had some abstraction over the library like if it was going to be replaced or like different implementation for mapping would be needed.
  • Basic API of the library didn’t change at all. 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.
  • In many of those projects AutoMapper was simply misused as code placed in 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:

  • Use AutoMapper only for simple mapping. Basically, one property to one property. Preferably, majority of property mapping is done by the same name. If you find yourself in situation when over half of your mappings are specified explicitly in ForMember method it may be the case for doing it manually (at least for the specific type) – it will be cleaner and less confusing.
  • If you have some logic to add to you mapping, do not add it via AutoMapper. Write a separate interface/class and use it (via DI) where your logic has to be applied. You will also be able to test it nicely in this way.
  • Do not abstract AutoMapper behind interfaces/implementations. I’ve seen abstracting this in a way that you need to create a class (empty in many cases) for each mapping type pair and somewhere there would be custom reflection code that initializes all of the mappings. Instead, use built-in AutoMapper 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.


14 comments


Just upgraded to AutoMapper 1.1 RTM

August 24, 2011 AutoMapper No comments

Just upgraded AutoMapper to 1.1 version. What is really funny about this update is that we used pre-release version of this tool in production. And it worked well, even there were some bugs, so I’m having some doubts if we relied on some of those bugs : ).

Here are Release notes we should benefit from:

For the 1.0 RTM: http://automapper.codeplex.com/releases/view/39791 For the 1.1 RTM: http://automapper.codeplex.com/releases/view/44802

Honestly I did not find some major changes and there were no obvious (compile error) breaking changes, even we used many of AutoMapper features. There are slight performance improvements and added features that we probably don’t need or maybe need. Thus I would like to complain about AutoMapper a bit – it is lacking documentation. Sometimes it is much easier to read about some feature and realize “aha, great, now we can utilize this capability!”.

There is only one hint to upgrading process I would like to add. When upgrading version I guess you would usually replace path to assembly in all *.csproj, but don’t be lazy and do full search in other files, as you might have different build/deploy scripts that push 3rdParty components to appropriate folders.


No comments


Allow set in your POCO or write crappy resolvers for AutoMapper or what?

December 20, 2010 AutoMapper, NHibernate 2 comments

In my project we are using NHibernate and Automapper to automatically map heavy database objects to light DTO object that we send across the wire. This works just fine, unless you have to map light object received to the POCO class.

Accordingly to all normal recommendations and just good common sense. You would not expose properties of your database objects with setter. Because ORM should fetch object graph in consistent state. And when you want to set Customer for Order you would probably use SetCustomer() method for better visibility and in

    public class Order
    {
        private Customer _customer = new Customer();
        public virtual int OrderId { get; set; }
        public virtual DateTime OrderDate { get; set; }
        public virtual Customer Customer { get { return _customer;}}
    }

and in mapping you would write something similar to this:

    public class OrderMap : ClassMap
    {
        public OrderMap()
        {
            WithTable("`Order`");

            Id(x => x.OrderId);
            Map(x => x.OrderDate, "OrderDate");

            References(x => x.Customer)
                .Access.AsCamelCaseField(Prefix.Underscore)
                .WithForeignKey("CustomerId");
        }
    }

as you can see, we set value for Customer using reflection deep inside of NHibernate. Also this approach ensures us that newly created Order will have default Customer object. But when we come to mapping OrderModel, which looks like below:

    [DataContract]
    public class OrderModel
    {
        [DataMember]
        public virtual int OrderId { get; set; }
        [DataMember]
        public virtual DateTime OrderDate { get; set; }
        [DataMember]
        public virtual CustomerModel Customer { get; set; }
    }

OrderModel.Customer simply doesn’t map to Order.Customer, since AutoMapper doesn’t have access to write into that value. Sadly, but AutoMapper doesn’t have any convention like NHibernate                 .Access.AsCamelCaseField(Prefix.Underscore), which means that it will look for _customer.

And now! AutoMapper is much smarter than NHibernate. You don’t need any conventions you can simply put private set and you are good! So I did:

    public class Order
    {
        private Customer _customer = new Customer();
        public virtual int OrderId { get; set; }
        public virtual DateTime OrderDate { get; set; }
        public virtual Customer Customer
        {
         get { return _customer;}
         private set { _customer = value;}
        }
    }

Honestly I wouldn’t write this post if I had knew about this possibility before I started writing it. But since I wrote more than half of what you see I decided to finish the story. Enjoy or blame me. Anyway for myself I took following: sniff around features and components you are using, some of them have better ideas than others, your task is to absorb the best!


2 comments


Developer’s Meeting: AutoMapper

July 22, 2010 AutoMapper, DevMeeting, Presentation, Success 12 comments

Today I performed developer’s meeting on AutoMapper. I would say that it went good, but I did not really enjoy it and will explain why. But I do not regret doing this presentation and will explain why.

Why am I upset of today’s presentation delivery?

Not so many people got interested in theme, that I’ve decided to present. There were about 10 or less developers in conference room. I really expected to have bigger audience and had prepared to speak to other division of our software business unit. But I believe there are some reasons why I did not get many listeners.

Few important thoughts for presenters that encounter the same

Never be disappointed by the number of attendees.. at least at the beginning, so this will not decrease quiality of your speach.

If topic of you speech is not really popular it doesn’t mean that you should discount its value.

If topic is indeed simple don’t neglect your preparations. For some reason I even wasn’t a bit nervous before presentation, as I’m usually are and I don’t find this to be good.

Take a look around, you probably will see those who are interested in topic and those who are simply excited by your presentations. Special thank to today’s attendees, without you I would have to talk to walls.

For future pay more attention on actuality and popularity of the topic. I personally going to create monkeysurvey to get that information.

With smaller audience you get more feedbacks. Why? Easily, they feel more relaxed and you have more time to allocate to each of them. In today’s presenation I got so many interesting questions and figured them out for myself and for audience online, while writing code. That was amazing.

Try to understand those who did not participate. Probably they counted to be more reasonable to spend that hour on some urgent issues or they discounted topic, since they are sure that will not need AutoMapper. And if they even will need it, it is quite possible to learn it in amount of couple of hours.

Still be proud of yourself. This is must be, otherwise you will lose confidence which costs a lot.

Presentation

For my presentation I’ve used already existing posts on AutoMapper, also for the end of presentation I had real world usage examples.

And here is presentation itself:

View more presentations from Andriy Buday.

Don’t forget to check out my article on AutoMapper here.


12 comments


Question about AutoMapper Performance

February 28, 2010 .NET, AutoMapper, Frameworks 4 comments

If you haven’t read my previous article on AutoMapper, please read it first.

After I’ve posted this article one guy was really concerned about the performance of AutoMapper.
So, I have decided to measure execution time of the AutoMapper mapping and manual mapping code.

First of all I have code which returns me 100000 almost random Customers which goes to the customers list.

Measurement of AutoMapper mapping time:

            stopwatch.Start();
            var autoMapperCVI = new List<CustomerViewItem>();
            foreach (var customer in customers)
            {
               autoMapperCVI.Add(Mapper.Map<Customer,CustomerViewItem>(customer));
            }
            stopwatch.Stop();
            Console.WriteLine(string.Format(“AutoMapper: {0}”, stopwatch.ElapsedMilliseconds));

Measurement of the manual mapping time:

            stopwatch.Start();
            var manualCVI = new List<CustomerViewItem>();
            foreach (var customer in customers)
            {
                var customerViewItem = new CustomerViewItem()
                                           {
                                               FirstName = customer.FirstName,
                                               LastName = customer.LastName,
                                               FullName = customer.LastName + ” “ + customer.FirstName,
                                               DateOfBirth = customer.DateOfBirth.ToLongDateString(),
                                               CompanyName = customer.Company.Name,
                                               NumberOfOrders = customer.NumberOfOrders,
                                               VIP = customer.VIP ? “Y” : “N”
                                           };
                manualCVI.Add(customerViewItem);
            }
            stopwatch.Stop();           
            Console.WriteLine(string.Format(“Manual Mapping: {0}”, stopwatch.ElapsedMilliseconds));

I ran my tests many times and one of the possible outputs could be:

AutoMapper: 2117
Manual Mapping: 293

It looks like manual mapping is 7 times faster than automatical. But hey, it took 2 sec to map handrend thouthands of customers.

It is one of the situations where you should decide if the performance is so critical for you or no. I don’t think that there are a lot of cases when you really need to choice manual mapping exactly because of performance issue.


4 comments


I wanna be not so noisy and decoupled to AutoMapper

February 27, 2010 .NET, AutoMapper, Clean Code 2 comments

If you haven’t read my previous article on AutoMapper, please read it first.

I just read an article on the noisiness which could be introduced with AutoMapper.

My Mapping Code is Noisy

Accordingly to that article my code:

   CustomerViewItem customerViewItem = Mapper.Map<CustomerCustomerViewItem>(customer);

is noisy code.

Why?

In few words that is because I’m coupled to the specific mapping engine and because I’m providing too much unneeded information on about how to map my objects.
Take a look on that line once again: we used Customer , but we already have customer, so we can know its type.


What to do to make it not so noisy?


In that article, that I pointed, there is proposition to change my code to:


            CustomerViewItem customerViewItem = customer.Map<CustomerViewItem>();


So, I’ve got interested to apply it to my previous AutoMapper article’s code. As you already caught Map is just extension method for my Customer  class.


Here it is:

    public static class MappingExtentions
    {
        public static TDest Map<TDest>(this Customer customer)
        {
            return Mapper.Map<Customer, TDest>(customer);
        }
    }

Everything becomes simple if you are trying it.


2 comments


AutoMapper

February 25, 2010 .NET, AutoMapper, Frameworks 4 comments

The Problem

Have you ever faced need to write code, which looks like here:

            Customer customer = GetCustomerFromDB();

            CustomerViewItem customerViewItem = new CustomerViewItem()
                                       {
                                           FirstName = customer.FirstName,
                                           LastName = customer.LastName,
                                           DateOfBirth = customer.DateOfBirth,
                                           NumberOfOrders = customer.NumberOfOrders
                                       };

            ShowCustomerInDataGrid(customerViewItem);

Our scenario could be like:
We have our domain model which has Customer entity and we are going to show Customers in DataGrid, and for that we need much lighter object CustomerViewItem, list of which is bounded to the Grid.

As you see there are four lines of code which are just copying values from one object to another. Could also be that you will need to show up to 10-15 columns in you grid. What then?

Would you like to have something that will do mapping from Customer to the CustomerViewItem automatically?

Of course you do, especially if you have another situation like mapping of heavy data objects into DTO objects which are considered to be send though the wire.

AutoMapper

From the AutoMapper codeplex web page we see that “AutoMapper is an object-object mapper. Object-object mapping works by transforming an input object of one type into an output object of a different type. What makes AutoMapper interesting is that it provides some interesting conventions to take the dirty work out of figuring out how to map type A to type B. As long as type B follows AutoMapper’s established convention, almost zero configuration is needed to map two types.“, so in other words it provides the solution for our problem.

To get started go and download it here. It is standalone assembly, so you should not get difficulties with including reference to it in your project.

So in order to ask AutoMapper do dirty work instead of me, we need to add next line somewhere in the start of our code execution:

            Mapper.CreateMap<Customer, CustomerViewItem>();

Once we have that we are done and we can use pretty nice code to get our mapped object:

            Customer customer = GetCustomerFromDB();

            CustomerViewItem customerViewItem = Mapper.Map<Customer, CustomerViewItem>(customer);

            ShowCustomerInDataGrid(customerViewItem);

Lets take a look on whole code base to see all about what I’m going to talk further:

    class Program
    {
        static void Main(string[] args)
        {
            var program = new Program();
            Mapper.CreateMap<Customer, CustomerViewItem>();
            program.Run();
        }

        private void Run()
        {
            Customer customer = GetCustomerFromDB();

            CustomerViewItem customerViewItem = Mapper.Map<Customer, CustomerViewItem>(customer);

            ShowCustomerInDataGrid(customerViewItem);
        }

        private void ShowCustomerInDataGrid(CustomerViewItem customerViewItem){}

        private Customer GetCustomerFromDB()
        {
            return new Customer()
            {
                DateOfBirth = new DateTime(1987, 11, 2),
                FirstName = “Andriy”,
                LastName = “Buday”,
                NumberOfOrders = 7
            };
        }
    }

    public class Customer
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public DateTime DateOfBirth { get; set; }

        public int NumberOfOrders { get; set; }
    }

    public class CustomerViewItem
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public DateTime DateOfBirth { get; set; }

        public int NumberOfOrders { get; set; }
    }


   
And proving that all values has been mapped take a look on the picture:

More Complex Example 1 (Custom Map)

So far we know all to have extremely simple mapping. But what if we need something more complex, for example, CustomerViewItem should have FullName, which consists with First and Last names of Customer?

After I just added public string FullName { get; set; } to the CustomerViewItem and run my application in debug I got null value in that property. That is fine and is because AutoMapper doesn’t see any FullName property in Customer class. In order to “open eyes” all you need is just to change a bit our CreateMap process:

            Mapper.CreateMap<Customer, CustomerViewItem>()
                .ForMember(cv => cv.FullName, m => m.MapFrom(s => s.FirstName + ” “ + s.LastName))


And results are immediately:

More Complex Example 2 (Flattening)

What if you have property Company of type Company:

    public class Customer
    {
        public Company Company { get; set; }
        //…
    }

    public class Company
    {
        public string Name { get; set; }
    }


and want to map it into CompanyName of the view class

    public class CustomerViewItem
    {
        public string CompanyName { get; set; }
        //…
    }


How do you think what do you need to change in your mapping to make this work?

Answer: NOTHING. AutoMapper goes in deep of your classes and if names matches it will do mapping for you.

More Complex Example 3 (Custom type resolvers)

What if you have boolean property VIP in your Customer class:

    public class Customer
    {
        public bool VIP { get; set; }
    }


and want to map it into string VIP and represent like “Y” or “N” instead

    public class CustomerViewItem
    {
        public string VIP { get; set; }
    }

   
Well, we can solve this the same way we did for the FullName, but more appropriate way is to use custom resolvers.
So lets create customer resolver which will resolve VIP issue for us.

It looks like:

    public class VIPResolver : ValueResolver<bool , string >
    {
        protected override string ResolveCore(bool source)
        {
            return source ? “Y” : “N”;
        }
    }


And only one line is needed for our CreateMap process:

    .ForMember(cv => cv.VIP, m => m.ResolveUsing<VIPResolver>().FromMember(x => x.VIP));

More Complex Example 4 (Custom Formatters)

What if I want AutoMapper to use my custom formatting of the DateTime instead of just using ToString, when it does mapping from DateTime to String property?
Let say I want use ToLongDateString method to show birth date with fashion.

For that we add:

    public class DateFormatter:IValueFormatter
    {
        public string FormatValue(ResolutionContext context)
        {
            return ((DateTime) context.SourceValue).ToLongDateString();
        }
    }


And making sure that AutoMapper knows where to use it:

                .ForMember(cv => cv.DateOfBirth, m => m.AddFormatter<DateFormatter>());
So, now I’ve got:

Great, isn’t it? BirthDate is even in my native language.

I hope my article was interesting to read and it gave you ideas how you can utilize this new feature called “AutoMapper”.


4 comments