asp.net-mvcviewmodel

What is ViewModel in MVC?


I am new to ASP.NET MVC. I have a problem with understanding the purpose of a ViewModel.

What is a ViewModel and why do we need a ViewModel for an ASP.NET MVC Application?

If I get a good example about its working and explanation that would be better.


Solution

  • A view model represents the data that you want to display on your view/page, whether it be used for static text or for input values (like textboxes and dropdown lists) that can be added to the database (or edited). It is something different than your domain model. It is a model for the view.

    Let us say that you have an Employee class that represents your employee domain model and it contains the following properties (unique identifier, first name, last name and date created):

    public class Employee : IEntity
    {
         public int Id { get; set; }
    
         public string FirstName { get; set; }
    
         public string LastName { get; set; }
    
         public DateTime DateCreated { get; set; }
    }
    

    View models differ from domain models in that view models only contain the data (represented by properties) that you want to use on your view. For example, lets say that you want to add a new employee record, your view model might look like this:

    public class CreateEmployeeViewModel
    {
         public string FirstName { get; set; }
    
         public string LastName { get; set; }
    }
    

    As you can see it only contains two of the properties. These two properties are also in the employee domain model. Why is this you may ask? Id might not be set from the view, it might be auto generated by the Employee table. And DateCreated might also be set in the stored procedure or in the service layer of your application. So Id and DateCreated are not needed in the view model. You might want to display these two properties when you view an employee’s details (an employee that has already been captured) as static text.

    When loading the view/page, the create action method in your employee controller will create an instance of this view model, populate any fields if required, and then pass this view model to the view/page:

    public class EmployeeController : Controller
    {
         private readonly IEmployeeService employeeService;
    
         public EmployeeController(IEmployeeService employeeService)
         {
              this.employeeService = employeeService;
         }
    
         public ActionResult Create()
         {
              CreateEmployeeViewModel model = new CreateEmployeeViewModel();
    
              return View(model);
         }
    
         public ActionResult Create(CreateEmployeeViewModel model)
         {
              // Do what ever needs to be done before adding the employee to the database
         }
    }
    

    Your view/page might look like this (assuming you are using ASP.NET MVC and the Razor view engine):

    @model MyProject.Web.ViewModels.CreateEmployeeViewModel
    
    <table>
         <tr>
              <td><b>First Name:</b></td>
              <td>@Html.TextBoxFor(m => m.FirstName, new { maxlength = "50", size = "50" })
                  @Html.ValidationMessageFor(m => m.FirstName)
              </td>
         </tr>
         <tr>
              <td><b>Last Name:</b></td>
              <td>@Html.TextBoxFor(m => m.LastName, new { maxlength = "50", size = "50" })
                  @Html.ValidationMessageFor(m => m.LastName)
              </td>
         </tr>
    </table>
    

    Validation would thus be done only on FirstName and LastName. Using FluentValidation you might have validation like this:

    public class CreateEmployeeViewModelValidator : AbstractValidator<CreateEmployeeViewModel>
    {
         public CreateEmployeeViewModelValidator()
         {
              RuleFor(m => m.FirstName)
                   .NotEmpty()
                   .WithMessage("First name required")
                   .Length(1, 50)
                   .WithMessage("First name must not be greater than 50 characters");
    
              RuleFor(m => m.LastName)
                   .NotEmpty()
                   .WithMessage("Last name required")
                   .Length(1, 50)
                   .WithMessage("Last name must not be greater than 50 characters");
         }
    }
    

    And with Data Annotations it might look this:

    public class CreateEmployeeViewModel : ViewModelBase
    {
        [Display(Name = "First Name")]
        [Required(ErrorMessage = "First name required")]
        public string FirstName { get; set; }
    
        [Display(Name = "Last Name")]
        [Required(ErrorMessage = "Last name required")]
        public string LastName { get; set; }
    }
    

    The key thing to remember is that the view model only represents the data that you want to use, nothing else. You can imagine all the unnecessary code and validation if you have a domain model with 30 properties and you only want to update a single value. Given this scenario you would only have this one value/property in the view model and not all the properties that are in the domain object.

    A view model might not only have data from one database table. It can combine data from another table. Take my example above about adding a new employee record. Besides adding just the first and last names you might also want to add the department of the employee. This list of departments will come from your Departments table. So now you have data from the Employees and Departments tables in one view model. You will just then need to add the following two properties to your view model and populate it with data:

    public int DepartmentId { get; set; }
    
    public IEnumerable<Department> Departments { get; set; }
    

    When editing employee data (an employee that has already been added to the database) it wouldn’t differ much from my example above. Create a view model, call it for example EditEmployeeViewModel. Only have the data that you want to edit in this view model, like first name and last name. Edit the data and click the submit button. I wouldn’t worry too much about the Id field because the Id value will probably been in the URL, for example:

    http://www.yourwebsite.com/Employee/Edit/3
    

    Take this Id and pass it through to your repository layer, together with your first name and last name values.

    When deleting a record, I normally follow the same path as with the edit view model. I would also have a URL, for example:

    http://www.yourwebsite.com/Employee/Delete/3
    

    When the view loads up for the first time I would get the employee’s data from the database using the Id of 3. I would then just display static text on my view/page so that the user can see what employee is being deleted. When the user clicks the Delete button, I would just use the Id value of 3 and pass it to my repository layer. You only need the Id to delete a record from the table.

    Another point, you don’t really need a view model for every action. If it is simple data then it would be fine to only use EmployeeViewModel. If it is complex views/pages and they differ from each other then I would suggest you use separate view models for each.

    I hope this clears up any confusion that you had about view models and domain models.