Using Automapper in .NET application to map client/server entities

Many times there comes a code where you map/convert objects between UI and service layers. For example, your project is WPF or MVC and you will be converting your view specific models to something that you can send to service as a request object or convert response from the service to the model entity that you can bind to the view.

Let’s see following code which you have written often to get this done:

var authorBooks = service.GetAuthorBooks();

            foreach (var item in authorBooks)
            {
                var AuthorBookViewModel viewModel = new AuthorBookViewModel
                {
                    Title = item.Title,
                    ISBN = item.ISBN,
                    PublishDate = item.PublishDate,
                    Publication = item.Publication,
                    Url = item.Url
                    Price = item.Price
                 };

                 this.BooksCollection.Add(AuthorBookViewModel);
             }

Listing 1.0 Manual mapping of client/server entities

The code in Listing 1.0 goes well as long there are few properties. But when it comes to map several properties like this, it becomes pain to do. Also when you add properties into the entities, you again need to revisit such code and make appropriate changes. Also if you need to use Mock data, you again write same code for mapping mock object to view model object.

AutoMapper

AutoMapper is a mapper between two objects. It maps two different entities. To achieve the same result as per Listing 1.0, you need to do two things:
1. Tell AutoMapper about the mapping relation.

Mapper.CreateMap<AuthorBookServiceModel, AuthorBookViewModel >();

2. Now use following code to get object of AuthorBookViewModel:
var viewModel =
   Mapper.Map< AuthorBookServiceModel, AuthorBookViewModel>(item);

You see! Lot of reduction of the code. Also it would be much managed when you have many objects with several properties to map. You can just create one class which you call on startup of application that will register all the class mapping with AutoMapper. And later a single place where you call out all the mapping and get your objects transformed for request and response.
What we have seen so far is very basic usage of Automapper. Let’s start with some real world scenarios to use it! First, create a C# Console application project. Add Automapper NuGet. More information about Automapper NuGet package can be found at:

https://www.nuget.org/packages/AutoMapper

Once we are done with AutoMapper NuGet package installation, Add following set of classes and methods defined:

public class AuthorBookServiceModel
    {
         public string Author { get; set; }
        public string Title { get; set; }
        public string ISBN { get; set; }

         public string Publication { get; set; }

         public string Url { get; set; }

         public double Price { get; set; }
        public DateTime PublishDate { get; set; }
    }

    public class AuthorBookViewModel
    {
         public string AuthorName { get; set; }
         public string Title { get; set; }
        public string ISBN { get; set; }

         public string Publication { get; set; }

         public string Url { get; set; }

         public double Price { get; set; }
        public DateTime PublishDate { get; set; }
    }
     class Program
    {
         static void Main(string[] args)
        {
            var program = new Program();
            Mapper.CreateMap<AuthorBookServiceModel, AuthorBookViewModel>();
             program.Run();
        }

         private void Run()
        {
            AuthorBookServiceModel authorBook = GetAuthorBooks();

            AuthorBookViewModel authorBookViewModel =
              Mapper.Map<AuthorBookServiceModel, AuthorBookViewModel>(authorBook);

            DisplayResult(authorBookViewModel);
           Console.ReadLine();
        }

        private void DisplayResult(
                       AuthorBookViewModel authorBookViewItem)
        {
           Console.WriteLine("Mapped AuthorBookViewModel object" + Environment.NewLine);
            
           Console.WriteLine(authorBookViewItem.Title);
           Console.WriteLine(authorBookViewItem.AuthorName);
           Console.WriteLine(authorBookViewItem.Price);
           Console.WriteLine(authorBookViewItem.Url);
           Console.WriteLine(authorBookViewItem.Publication);
           Console.WriteLine(authorBookViewItem.ISBN);
           Console.WriteLine(authorBookViewItem.PublishDate);
         }

        private AuthorBookServiceModel GetAuthorBooks()
         {
             return new AuthorBookServiceModel()
            {
                Author = "Ashish Ghoda",
                Title = "Windows 8 MVVM Patterns Revealed",
                Url = "http://www.apress.com/9781430249085",
                ISBN = "978-1-4302-4908-5",
                Price = 19.99,
                Publication = "Apress",
                PublishDate = new DateTime(2013, 1, 1)
             };
        }
    }

Listing 1.1 Sample code for AutoMapper examples

When you run the code as per listing 1.1, you will see that it shows all the property’s value displayed except AuthorName. This is because the other entity has Author property and we have not told AutoMapper to map Author to AuthorName. To fix this, we need to modify our mapping to following:

Mapper.CreateMap<AuthorBookServiceModel, AuthorBookViewModel>()
               .ForMember(dest => dest.AuthorName, opt => opt.MapFrom(source => source.Author));

Listing 1.2 Mapping properties with different name

Note that mapping works one way. Means Your mapping AuthorBookServiceModel to AuthorBookViewModel. So if you try to map reverse i.e. AuthorBookViewModel to AuthorBookServiceModel, you will get an exception. To make it work both ways and also map properties with different names, we need to use ReverseMap method as following:

            Mapper.CreateMap<AuthorBookServiceModel, AuthorBookViewModel>()
               .ForMember(dest => dest.AuthorName, opt => opt.MapFrom(source => source.Author)).ReverseMap();
Listing 1.3 Two-way mapping using ReverseMap
Let’s add property called FormattedPrice in AuthorBookViewModel. This will show $ sign with price of the book. To map it accordingly, we can do as per listing 1.4:
            Mapper.CreateMap<AuthorBookServiceModel, AuthorBookViewModel>()
               .ForMember(dest => dest.AuthorName, opt => opt.MapFrom(source => source.Author))
               .ForMember(dest => dest.FormattedPrice, m => m.MapFrom(source => "$" + source.Price));

Listing 1.4 Map property with string manipulation

Many times it happens that you show meaningful value in UI for Boolean or other properties. Like Yes/No, Available/Not Available for Boolean values. We will learn how to map Boolean property to Text property via AutoMapper. For this, add IsAvailable boolean property in AuthorBookServiceModel.

public bool IsAvailable { get; set; }

Also add Status string property in AuthorBookViewModel.
        
public string Status { get; set; }

Now let’s add ValueResolver for this as per following code:

public class StatusResolver : ValueResolver<bool, string>
         {
             protected override string ResolveCore(bool source)
             {
                 return source ? "Available" : "No available";
            }
        }

Now listing 1.5 below shows how to use this StatusResolver with AutoMapper.

Mapper.CreateMap<AuthorBookServiceModel, AuthorBookViewModel>()
               .ForMember(dest => dest.AuthorName, opt => opt.MapFrom(source => source.Author))
               .ForMember(dest => dest.FormattedPrice, m => m.MapFrom(source => "$" + source.Price))
               .ForMember(dest => dest.Status, c => c.ResolveUsing<StatusResolver>().FromMember(source => source.IsAvailable))
               .ReverseMap();

Listing 1.5 Map using value resolver

Source code is available here.

By jay nanavati   Popularity  (2127 Views)