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.
What ViewModel is. In ASP.NET MVC, ViewModels are used to shape multiple entities from one or more models into a single object. This conversion into single object provides us better optimization.
ViewModel is a class that is responsible for preparing and managing the data for an Activity or a Fragment . It also handles the communication of the Activity / Fragment with the rest of the application (e.g. calling the business logic classes).
A model is usually more closely related to how your data is stored (database, services, etc.) and the model will closely resemble those. The ViewModel on the other hand is closely related to how your data is presented to the user. It is usually a flatten version of your model, denormalized, etc.
In ASP.NET MVC, ViewModel is a class that contains the fields which are represented in the strongly-typed view. It is used to pass data from controller to strongly-typed view.
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.
View model is a class that represents the data model used in a specific view. We could use this class as a model for a login page:
public class LoginPageVM { [Required(ErrorMessage = "Are you really trying to login without entering username?")] [DisplayName("Username/e-mail")] public string UserName { get; set; } [Required(ErrorMessage = "Please enter password:)")] [DisplayName("Password")] public string Password { get; set; } [DisplayName("Stay logged in when browser is closed")] public bool RememberMe { get; set; } }
Using this view model you can define the view (Razor view engine):
@model CamelTrap.Models.ViewModels.LoginPageVM @using (Html.BeginForm()) { @Html.EditorFor(m => m); <input type="submit" value="Save" class="submit" /> }
And actions:
[HttpGet] public ActionResult LoginPage() { return View(); } [HttpPost] public ActionResult LoginPage(LoginPageVM model) { ...code to login user to application... return View(model); }
Which produces this result (screen is taken after submitting form, with validation messages):
As you can see, a view model has many roles:
LabelFor
,EditorFor
,DisplayFor
helpers).Another example of a view model and its retrieval: We want to display basic user data, his privileges and users name. We create a special view model, which contains only the required fields. We retrieve data from different entities from database, but the view is only aware of the view model class:
public class UserVM { public int ID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public bool IsAdministrator { get; set; } public string MothersName { get; set; } }
Retrieval:
var user = db.userRepository.GetUser(id); var model = new UserVM() { ID = user.ID, FirstName = user.FirstName, LastName = user.LastName, IsAdministrator = user.Proviledges.IsAdministrator, MothersName = user.Mother.FirstName + " " + user.Mother.LastName }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With