Click here to Skip to main content
15,885,026 members
Articles / MVC

ASP.NET MVC ViewModel Value Formatting using AutoMapper

Rate me:
Please Sign up or sign in to vote.
4.67/5 (2 votes)
5 Jan 2010CPOL2 min read 21.6K   6  
ASP.NET MVC ViewModel Value Formatting using AutoMapper.
From ASP.NET MVC in Action section 4.4.1:

Views are difficult to unit test, so we want to keep them as thin as possible. … Notice in [the View Model] that all of the properties are strings. We’ll have the [properties] properly formatted before this view model object is placed in view data. This way, the view need not consider the object, and it can format the information properly.

To facilitate the formatting between the Domain Model and the View Model, a few of AutoMapper’s features may be utilized. Here’s a DomainModel containing a CurrencyProperty which will needed to formatted for human consumption:

public class DomainModel

{

    public decimal CurrencyProperty { get; set; }

}

Now, here is a ViewModel which will be used to transport the formatted value to the View:

public class ViewModel

{

    ///<summary>Currency Property - formatted as $#,###.##</summary>

    public string CurrencyProperty { get; set; }

}

Mapping from Domain Model to View Model

AutoMapper provides an easy way to create a mapping between two object types.  For particular tweaks for individual property mappings, the “.ForMember()” method can be used like:

///<summary>Setup mapping between domain and view model</summary>

static ViewModel()

{

    // map dm to vm

    Mapper.CreateMap<DomainModel, ViewModel>()

      .ForMember(vm => vm.CurrencyProperty, mc => mc.AddFormatter<CurrencyFormatter>());

}

This sets up a mapping between the DomainModel and ViewModel and additionally applies a custom formatter for CurrencyProperty.  The formatter must implement the IValueFormatter interface like so:

public class CurrencyFormatter : IValueFormatter

{

    ///<summary>Formats source value as currency</summary>

    public string FormatValue(ResolutionContext context)

    {

        return string.Format(CultureInfo.CurrentCulture, "{0:c}", context.SourceValue);

    }

}

…and a simple conversion constructor on the ViewModel:

/// <summary> Creates the view model from the domain model.</summary>

public ViewModel(DomainModel domainModel)

{

    Mapper.Map(domainModel, this);

}

Now, neither the Controller or View need concern about any formatting and can stay focused on orchestrating and layout:

public ViewResult Index()

{

    var model = new DomainModel{CurrencyProperty = 19.95m};



    var viewModel = new ViewModel(model);



    return View(viewModel);

}
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<ViewModel>" %>

<asp:Content ContentPlaceHolderID="MainContent" runat="server">

<% using(Html.BeginForm()) {%>

    <%= Html.TextBoxFor(m=>m.CurrencyProperty)%>

<%} %>

</asp:Content>

Aside: TextBoxFor is an upcoming MVC 2 feature that’s available today in MVC Futures or the RC.  Check out Matt’s post for some neat stuff.

Mapping from View Model back to Domain Model

So now the formatted value is being rendered – but how do we go about the reverse trip back to the server?  First, to define an action:

[AcceptVerbs(HttpVerbs.Post)]

public ActionResult Index(ViewModel viewModel)

{

    var model = new DomainModel();

    

    viewModel.MapTo(model);



    // ... return a view or action result

}

Aside: for validating that what the user enters is in the correct format, see another post about jQuery Validate here .

… and a Map method on the ViewModel:

public void MapTo(DomainModel domainModel)

{

    Mapper.Map(this, domainModel);

}

But this mapping will fail without first creating a definition back from the ViewModel to the Model.  In the ViewModel’s static constructor:

// from vm to dm

Mapper.CreateMap<ViewModel, DomainModel>()

 .ForMember(dm => dm.CurrencyProperty,

  mc => mc

   .ResolveUsing<CurrencyResolver>()

   .FromMember(vm => vm.CurrencyProperty));

This utilizes another AutoMapper method 0 ResolveUsing - which can be used to get the string property back to a decimal.  The ValueResolver<TSource,TDestination> is defined like so:

public class CurrencyResolver : ValueResolver<string, decimal>

{

    ///<summary>Parses source value as currency</summary>

    protected override decimal ResolveCore(string source)

    {

        return decimal.Parse(source, NumberStyles.Currency, CultureInfo.CurrentCulture);

    }

}

Conclusions

There may be more elegant ways to accomplish formatting for MVC Views, but this method is quite workable.  In particular, I can imagine utilizing DataAnnotations’s DisplayFormatAttribute to decorate the Model or ViewModel and the framework automagically applying the formatting while rendering the View.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --