Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Always use ViewModel pattern in MVC? [closed]

In MVC in the controller you should get the Model from DB and convert it to a ViewModel before sending it to the View. Typically using something like Automapper.

My question is, if you need to show all the properties of the Model in the view as they are, is creating a ViewModel worth it?

If the Model and ViewModel need to be the same, creating a ViewModel creates some security or benefits in the app or we are only adding unnecessary complexity?

like image 380
Ricardo Polo Jaramillo Avatar asked May 18 '14 14:05

Ricardo Polo Jaramillo


2 Answers

The point of using a view model is generally because your view requires more/less information than what your domain model provides.

Other benefits include decoupling your view from your domain which can cause fragility if your domain evolves.

The crux of it is, they aren't a necessity; the purpose of a view model is to provide the view with only the information it needs to render itself, if you feel a view model in your app would be redundant then don't use it. However, I would at least consider using an interface to avoid coupling.

like image 109
James Avatar answered Sep 28 '22 16:09

James


Besides what is already mentioned (separation of a concern,decoupling,etc), a separate ViewModel stops abstraction leaking that may come along with the DB Model. This is true especially if you are using EF with navigation properties enabled.

Let's say you have cars and wheels. You are showing the cars in the view.

Case 1 (No Separate ViewModel For cars): In the razor view, it is very easy to have something like below:

  public class CarModelFromDB
  {
      public string CarName{get;set;}
      //More properties
      public IEnumerable<Wheel> Wheel{get;set;}
  }  

  @model IEnumerable<CarModelFromDB>

  @foreach(var car in Model)
  {
      //some View Code
      @foreach(var wheel in car.Wheels.Where(x=>x.IsRound=true))
      {
         <span>wheel.Color</span> 
         // some View Code
      }
  }

Now, your logic for getting wheels with the cars has leaked into the view and also has enabled select N+1 situation. I don't think there is any easy ways of testing it either.

Case 2 (With ViewModel For cars): In this scenario, you can restrict the view by sending only things that it needs. It may look like below:

  public class CarViewModel
  {
      public string CarName{get;set;}
      //More properties
      public IEnumerable<string> WheelColors{get;set;}
  }  

  @model IEnumerable<CarViewModel>
  @foreach(var car in Model)
  {
      //some View Code
      @foreach(var wheelColor in WheelColor)
      {
         <span>wheelColor</span> 
         // some View Code
      }
  }

Now, your view code is very restricted in terms of what it can do, and it won't send any rogue queries to the database. Your controller is truly in control of what view is getting. You can push the wheel logic in there or ideally in some service method that gets called from the action method. Also, you can do proper testing on the action method and feel confident in your system. I hope this helps.

Update

Case 3 (dynamic ViewModel): If you are comfortable with dynamic types, you can avoid all the casting and mapping. As long as your view gets the properties it needs, it will be happy. It does not matter where those come from. So the code will be:

  public class CarViewModel
  {
      public string CarName{get;set;}
      //More properties
      public IEnumerable<string> WheelColors{get;set;}
  }  

  // pass the List<CarViewModel> to the view

  @model dynamic
  @foreach(var car in Model)
  {
      //some View Code
      @foreach(var wheelColor in WheelColor)
      {
         <span>wheelColor</span> 
         // some View Code
      }
  }

The potential downside/extra work is to make sure you have tests for the existence of those properties on the model.

Again like it is mentioned earlier, this should not be considered as the one size fit all type of solution. These are some options and used only if they make sense.

like image 21
Yogiraj Avatar answered Sep 28 '22 18:09

Yogiraj