View Models in ASP.NET MVC

In ASP.NET MVC best practice is to use view models. A view model in ASP.NET MVC is a simple class only containing the data, that you want to display on your view. A view model can contain all from static text to input values like an assortment of countries for a drop-down menu.

Let’s say that we have an Employee class and it contains the following properties.

using System;

namespace ViewModelExample.Models
{
    public class Employee
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public DateTime DateCreated { get; set; }
    }
}

We want to be able to create a new Employee and add it to a database. One way to do this would be to set the Employee class as the model in the view. The bad thing about that strategy is that it will send out the DateCreated and the Id properties to the view.

Instead of doing that we will create a view model only containing the data we want to display on the view.

namespace ViewModelExample.Models
{
    public class CreateEmployeeViewModel
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
}

Notice that ‘ViewModel’ is part of the class name, the reason for this is a naming convention to easy spot view models from domain models. Another thing is that it contains the verb ‘Create’ to specify that it is for the Create Action in the Employee Controller. You don’t have to follow the action name prefix, but the ‘ViewModel’ part of the view model will help you in the future when searching and handling files.

As you can see in the view model we created, it only contains two properties from the domain model. The ‘Id’ is not there because it will be autogenerated and accordingly no reason to make it available in the view. The same thing with the ‘DateCreated’ property which will be made on the creation of the employee.

Using a view model in a controller

Now that we have created a view model we want to make use of it. So in the Employee controllers “Create” action, we create a new view model and pass it to the view.

using System.Web.Mvc;
using ViewModelExample.Models;
using ViewModelExample.Viewmodels;

namespace ViewModelExample.Controllers
{
    public class EmployeeController : Controller
    {
        public ActionResult Create()
        {
            var vm = new CreateEmployeeViewModel();

            return View(vm);
        }

        [HttpPost]
        public ActionResult Create(CreateEmployeeViewModel vm)
        {
            var employee = new Employee
            {
                FirstName = vm.FirstName,
                LastName = vm.LastName
            };

            // Save the Employee to an database

            return View("Index", "Home");
        }
    }
}

In the above code, there are two very simple implementations of using a view model, one for the GET request and one for the POST request.

If we take a look at the POST method implementation we can see that there is a mapping happening from the view model to the domain model. The reason for this is that we don’t want to send the view model down to the domain layer, the view model is only created to act as a data structure for the view and not a data structure to be operated on, in the domain layer.

You can do the mapping manually like it is being implemented in the example above or you can use a mapping framework like Automapper, I have created a guide on it here.

View models in Razor views

To use a view model in the standard view rendering framework for ASP.NET, Razor, you define the model as you normally would at the top of the file with the @model syntax.

A thing to notice if you’re not very familiar with ASP.NET MVC Razor views is that you can use the @Html helper methods to make your view strongly typed, so you will get IntelliSense and if your view model changes you will get build errors and therefore have an easier time dealing with application changes.

The following code shows a simple implementation of using a view model in an HTML form with two labels and two text boxes.

@model ViewModelExample.Viewmodels.CreateEmployeeViewModel

@{
    ViewBag.Title = "title";
}

@using (Html.BeginForm("Create", "Employee", FormMethod.Post))
{
    <div class="form-group">
        @Html.LabelFor(e => e.FirstName)
        @Html.TextBoxFor(e => e.FirstName)
    </div>

    <div class="form-group">
        @Html.LabelFor(e => e.LastName)
        @Html.TextBoxFor(e => e.LastName)
    </div>

    <button type="submit">Create</button>
}

Data annotations on view models

If you’re not familiar with data annotations, here comes a very quick introduction. A data annotation is a way to declare an attribute to a property, this can be the max string length that the property can hold or what text it should display using a strongly typed view (normally it displays the property name). Data annotations can be very useful on view models because instead of writing all the data validation yourself you can use data annotations and get very quick validation on the data being passed from the views to the controllers.

Using the data annotations that you can see in the code below, we now have validation on the server. If the user tries to create an employee with invalid data according to the data annotations applied to the properties, an error will be thrown displaying what went wrong to the user.

using System.ComponentModel.DataAnnotations;

namespace ViewModelExample.Viewmodels
{
    public class CreateEmployeeViewModel
    {
        [Display(Name = "First name")]
        [MinLength(2)]
        [MaxLength(50)]
        public string FirstName { get; set; }

        [Display(Name = "Last name")]
        [MinLength(4)]
        [MaxLength(50)]
        public string LastName { get; set; }
    }
}

Below is an example of using the MaxLength and MinLength annotation, showing the error messages that are displayed if the annotation is being triggered.

Form using a view mdoel

To show the validation as seen above you insert the following code into the view:

<div class="form-group">
    @Html.LabelFor(e => e.LastName)
    @Html.TextBoxFor(e => e.LastName)
    @Html.ValidationMessageFor(m => m.LastName)
</div>

As well as adding ModelState.IsValid to your controller, to redirect the user back to the view if the view model contains bad data.

[HttpPost]
public ActionResult Create(CreateEmployeeViewModel vm)
{
    if (!ModelState.IsValid)
        return View("Create", vm);

    var employee = new Employee
    {
        FirstName = vm.FirstName,
        LastName = vm.LastName
    };

    // Save the Employee to an database
    return RedirectToAction("Index", "Home");
}

It is essential to use server-side validation. Using data annotations on view models are one way of doing it, but try to always use client-side validation because it will give a smoother experience for the user as well as reduce the number of server requests.