Pages

Friday, April 13, 2012

View Model pattern and AutoMapper in ASP.NET MVC Applications

In real world ASP.NET MVC applications, we have to use model objects specially designed for our ASP.NET MVC views. Domain objects are designed for the needs for domain model and it is representing the domain of our applications. On the other hand, View Model objects designed for our needs for views.

The below is the domain model of our demo



We have a Contact domain entity that has a association with Contact Group. While we creating a new Contact, we have to specify that in which contactgroup belongs with the new contact.

The below is the user interface for creating a new contact
 


The above new contact UI has the form fields for representing the Contact entity and a GroupId field for representing the contact group.

The below is the class for Contact View Model

public class ContactViewModel
{
public int Id
{
    get;
    set;
}
[Required(ErrorMessage = "FirstName Required")]
[StringLength(25, ErrorMessage = "Must be less than 25 characters")]
public string FirstName
{
    get;
    set;
}
[Required(ErrorMessage = "LasttName Required")]
[StringLength(25, ErrorMessage = "Must be less than 25 characters")]
public string LastName
{
    get;
    set;
}      

[Required(ErrorMessage = "Email Required")]
[RegularExpression("^([0-9a-zA-Z]([-.\\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\\w]*[0-9a-zA-Z]\\.)+[a-zA-Z]{2,9})$", ErrorMessage = "Not a valid email")]
public string EMail
{
    get;
    set;
}
[Required(ErrorMessage = "Phone Required")]
public string Phone
{
    get;
    set;
}
public string Address
{
    get;
    set;
}
[Required(ErrorMessage = "GroupId Required")]     
public int GroupId
{
    get;
    set;
}
public IEnumerable<SelectListItem> ContactGroup
{
    get;
    set;
}

}

Our Contact View Model is designed for the purpose of View template and contains the all validation rules. It has properties for mapping values to Contact entity and a GroupId property for taking Id value from ContactGroup drop-down. And also providing a property ContactGroup for binding values to ContactGroup drop-down.
 The below code is Action method for Create Contact HttpGet request where we are creating an instance of Contact View Model and sets the Contactgroup property for binding values to drop-down list.
/HttpGet for the Create Contact
public ActionResult Create() {
    var viewModel = new ContactViewModel();
    var groups = contactRepository.ListGroups();
    viewModel.ContactGroup = groups.ToSelectListItems(-1);
    if (groups.Count<ContactGroup>() == 0)
        return RedirectToAction("Index", "Group");
    return View("Create", viewModel);
}

  The below code is Action method for Create Contact HttpPost request.
[HttpPost]
public ActionResult Create(ContactViewModel contactToCreate) {
if (ModelState.IsValid) {

    Contact newContact = new Contact();
    AutoMapper.Mapper.Map(contactToCreate, newContact);
    contactRepository.CreateContact(contactToCreate.GroupId, newContact);   
 }
}

In the above action method, our model binder is the ContactViewModel and we have to map values of ContactViewModel object to Domain model object Contact for the persistance purpose. In ASP.NET MVC applications, you have to map values between view model objects and domain model objects in many situations. In such scenarios, you can use AutoMapper for mapping values between objects to objects.In our code we copy values from our View model object ContactViewModel  to domain model object Contact. AutoMapper is a convention based object to object mapper framework developed by Jimmy Bogard.   A mapping configuration is a one time task and the below code setting map configuarion between our ContactViewModel and Contact.
Mapper.CreateMap<ContactViewModel,Contact>();
The below code copy values of ContactViewModel object to Contact object
AutoMapper.Mapper.Map(contactToCreate, newContact);
 Check the Flattening for mapping to take a complex object model and flatten it to a simpler model. AutoMapper is available at http://automapper.codeplex.com/ and the source code is hosted at http://code.google.com/p/automapperhome.

No comments: