Apr 14 2009

Using AutoMapper to map view models in ASP.NET MVC

Category: Uncategorizedbengtbe @ 06:27

In projects that have complex domain models it is often necessary to map the domain models to simpler objects such as Data Transfer Objects (DTO) which is “an object that carries data between processes in order to reduce the number of method calls” or Presentation Models which “represent the state and behavior of the presentation independently of the GUI controls used in the interface“.

The mapping code is often boring and tedious to write, so when I first read about AutoMapper it triggered my interest. In this post I will take a first look at AutoMapper, and show how it can be used to map a complex domain model to a view model in an ASP.NET MVC application.

About AutoMapper

The project homepage describes AutoMapper as “a fluent configuration API to define an object-object mapping strategy. AutoMapper uses a convention-based matching algorithm to
match up source to destination values. Currently, AutoMapper is geared towards model projection scenarios to flatten complex object models to DTOs and other simple objects, whose design is better suited for serialization, communication, messaging, or simply an anti-corruption layer between the domain and application layer.

AutoMapper is a fairly new project; the current version is 0.30 Beta, and it seems to be in active development.

A complex domain model

The domain model that I’m going to use in this example is a Customer class that has a reference to an Address class:

public class Customer

{

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public string Email { get; set; }

    public Address HomeAddress { get; set; }

    public string GetFullName()

    {

        return string.Format(“{0} {1}”, FirstName, LastName);

    }

}

The Address class is as follows:

public class Address

{

    public string Address1 { get; set; }

    public string Address2 { get; set; }

    public string City { get; set; }

    public string PostalCode { get; set; }

    public string Country { get; set; }

}

Ok, I admit that this domain model is not very complex, but it will serve the purpose of this post :)

The simple view model

The view is going to show a list of customers with name, email and country. We therefore create a view model called CustomerListViewModel:

public class CustomerListViewModel

{

    public string FullName { get; set; }

    public string Email { get; set; }

    public string HomeAddressCountry { get; set; }

}

I save this view model in the file ViewModel/Customers/CustomerListViewModel.cs in the web-project. In an ASP.NET MVC application the view models belong to the Web-project, they are not part of the domain model. Usually a view model belongs to a single controller, and its views.

The controller

The URL used to display the customers should be http://application/Customers/, hence the name of the controller is CustomersController, and the action used is the Index():

public class CustomersController : Controller

{

    private readonly ICustomerService m_CustomerService;

    public CustomersController(ICustomerService customerService)

    {

        m_CustomerService = customerService;

    }

    // GET: /Customers/

    public ActionResult Index()

    {

        IList<Customer> customers = m_CustomerService.GetCustomers();

        Mapper.CreateMap<Customer, CustomerListViewModel>();

        IList<CustomerListViewModel> viewModelList =

           Mapper.Map<IList<Customer>, IList<CustomerListViewModel>>(customers);

        return View(viewModelList);

    }

}

In the above controller I use Dependency Injection to inject the CustomerService in the constructor. In a previous post I have shown how to use Dependency Injection in the controllers.

When using AutoMapper you first have to create a map between the two classes:

Mapper.CreateMap<Customer, CustomerListViewModel>();

The following line maps the list of Customers to a list of CustomerListViewModel:

IList<CustomerListViewModel> viewModelList =

   Mapper.Map<IList<Customer>, IList<CustomerListViewModel>>(customers);

If you just wanted to map a single instance you would use:

CustomerListViewModel viewModel = Mapper.Map<Customer, CustomerListViewModel>(customer);

AutoMapper will perform the following mapping automatically:

  • FullName gets its value by calling the Customer.GetFullName() method.
  • Email gets its value from the Customer.Email propery.
  • HomeAddressCountry gets its value from the Customer.HomeAddress.Country property.

The view

Below is the view used to display the view model:

<%@ Page Title=”" Language=”C#” MasterPageFile=”~/Views/Shared/Site.Master”

       Inherits=”System.Web.Mvc.ViewPage<IEnumerable<CustomerListViewModel>>” %>

<%@ Import Namespace=”MyApp.Web.ViewModels.Customers”%>

<asp:Content ID=”Content1″ ContentPlaceHolderID=”MainContent” runat=”server”>

    <h2>Customer list</h2>

    <table>

        <tr>

            <th>Name</th>

            <th>Email</th>

            <th>Country</th>

        </tr>

    <% foreach (var customer in Model) { %>

        <tr>

            <td><%= Html.Encode(customer.FullName) %></td>

            <td><%= Html.Encode(customer.Email) %></td>

            <td><%= Html.Encode(customer.HomeAddressCountry) %></td>

        </tr>

    <% } %>

    </table>

</asp:Content>

<asp:Content ID=”Content2″ ContentPlaceHolderID=”head” runat=”server”></asp:Content>

As you can see from the Inherits attribute, this view is strongly typed to the IEnuerable<CustomerListViewModel>. The foreach uses the Model property to retrieve the list of CustomerListViewModel, and creates a table row for each instance.

Some advanced features of AutoMapper

In the example above I have shown some simple usages of AutoMapper. I will now take a quick look at some of its more advanced features:

Let’s say that the Customer has a Birthday property of type DateTime that we want to map to a YearOfBirth property of type int:

Mapper.CreateMap<Customer, CustomerListViewModel>()

    .ForMember(dest => dest.YearOfBirth, opt => opt.MapFrom(src => src.Birthday.Year));

Don’t get confused by all the lamdas (=>). The ForMember method just says YearOfBirth should get its value from Birthday.Year.

AutoMapper can also help you test the mapping:

[Test]

public void Should_be_able_to_map_Customer_to_CustomerListViewModel()

{

    Mapper.CreateMap<Customer, CustomerListViewModel>()

        .ForMember(dest => dest.ThisIsMappedElsewhere, opt => opt.Ignore());

    Mapper.AssertConfigurationIsValid();

}

In the above test AutoMapper will check to make sure that every single member on CustomerListViewModel has a corresponding member on the Customer, except for the property ThisIsMappedElsewhere that we told it to ignore.

There are many more features that I haven’t covered. You can find more information in the following places:

kick it on DotNetKicks.com Shout it

Tags: ,

9 Responses to “Using AutoMapper to map view models in ASP.NET MVC”

  1. Jimmy Bogard says:

    Looks great! One suggestion I’d have – we put all of our CreateMap code into one place, and that is executed once in our Global.asax Application_Start event. Our unit test is then two lines – MapperConfiguration.Configure, then Mapper.AssertConfigurationIsValid.

  2. bengtbe says:

    Looks great! One suggestion I’d have – we put all of our CreateMap code into one place, and that is executed once in our Global.asax Application_Start event. Our unit test is then two lines – MapperConfiguration.Configure, then Mapper.AssertConfigurationIsValid.

    Thanks for the tip! Sounds like a good idea!

  3. Geofrey Braaf says:

    Now this is one handy piece of code! I’m going to play with this today. Thanx for the introduction.

    @bengtbe: I second that! Would make it even cleaner. On the other hand, you could simply move all mapping code into a helper class with some static methods. I do something similar with (Fluent)Validation.

  4. Jones says:

    Nice Blog…

  5. dsd-sico says:

    This looks great! But what about validation?

    Should validation be inside the Domain Model ("of course!" I hear you screaming :) . But should a View Model contain validationcode as well? If so, wouldn’t that be against the "Don’t repeat yourself" commandment? :)

    Or would it be more logical to seperate validation using Fluent validation. Then the Domain Model as well as the View Model use and share the validation code?

  6. bengtbe says:

    Thanks for your comment dsd-sico,

    You raises valid questions regarding validation, but I deliberately left this out of this post. Hence I only showed how to map from the domain model to the view model. The "mapping" from view model to domain model is often more complex (e.g. validation) and might not be suitable for AutoMapper. Take a look at this post where this is discussed: http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/09/17/the-case-for-two-way-mapping-in-automapper.aspx.

    Your other questions regarding validation is to big to answer here in the comments, as it depends on the requirements of the project. In some project all the validation can be inside the domain model, in others all can be outside the domain model, and in some you need validation in both places.

    In the last section I assume you are referring to the The Fluent Validation project. This project certainly looks interesting, but I haven’t had time to look into it.

  7. SEO says:

    MVC does not specifically mention the data access layer because it is understood to be underneath or encapsulated by the model. Models are not data access objects although in very simple apps, with little domain logic, there is no real distinction to be made.

  8. ankur says:

    can you please attached your sample project for this.

  9. Bengt Berge says:

    Hi ankur. Sorry I no longer have the code that this post was based on.

Leave a Reply