Asp.net-mvc – ASP.NET MVC – How exactly to use View Models

asp.net-mvcviewmodel

Let's say I have a page that allows the editing of a user's details, so I have a ViewModel like this:

public class UserViewModel {
    public string Username { get; set; }
    public string Password { get; set; }
    public int ManagerId { get; set; }
    public string Category { get; set; }
}

So on my EditUser action I can have this passed back by the model binder and then I can map that to the Domain Model:

public ActionResult EditUser(UserViewModel user) {
    ...

However, the page that displays the form also needs details such as a list of Managers and Categories to provide dropdowns for those fields. It might also display a list of other users in a sidebar so you can switch between the different users you're editing.

So then I have another view model:

public class ViewUserViewModel {
    public UserViewModel EditingUser { get; set; }
    public IEnumerable<SelectListItem> Managers { get; set; }
    public IEnumerable<SelectListItem> Categories { get; set; }
    public IEnumerable<SelectListItem> AllUsers { get; set; }
}

Is this the correct way to do it? Are they both View Models? If so, is there a naming convention I should use so I can distinguish between VMs that are like models and VMs that just contain data for the page?

Have I got this all wrong?

Best Answer

"View Model" is just a pattern. There's nothing magical about the name, but generally any class being passed to a view (whether for simply displaying data or for the purposes of form submissions) is referred to as a "view model" and given a name like FooViewModel or FooVM to indicate that it's part of that "view model" pattern.

I don't want to go too philosophical on you, but I think a little bit of reference about the patterns in play will be helpful. ASP.NET MVC obviously enough encourages an MVC (Model-View-Controller) architectural model. In MVC the Model is the container for all the application's business logic. The Controller is responsible for handling the request, fetching the model, rendering the View with that model and returning a response. That seems like a lot of responsibility but in actuality the framework handles most of this behind the scenes, so Controllers are typically (and should be) very light on code. They are responsible for the bare minimum amount of functionality to wire everything up. Finally, the View is responsible for creating the UI layer that allows the user to interact with the data in the Model. It is not responsible for the data itself, nor should it be (ViewData/ViewBag is a pretty big violation here, at least in as much as the way it ends up being used by developers in practice).

So, that means the bulk of your application logic should be in your model, and typically that's a good thing. However, since the model is the haven of application data, it generally gets persisted in a database or similar. That creates some conflict of interest as you now need to start a balancing act between what data should be persisted and what data should only exist for the purpose of display.

This is where view models come in. MVVM (Model-View-View Model), a somewhat parallel pattern to MVC, recognizes the inherent issues in a one-model-to-rule-them-all approach. I won't go into much detail here, because MVC doesn't use this pattern. However, most ASP.NET MVC developers have co-opted the View Model of MVVM. What you essentially end up with is a database-backed entity (the traditional model) and then usually many different view models that represent that entity in various states. This allows your model to contain the business logic that's relevant to persistence while the view model(s) contain the business logic relevant to displaying, creating and updating that model.

I've gone off track a little, but the long and short is that what you're doing is perfectly acceptable. In fact, it's good practice. Create as many view models as your application requires, and use them to actually store the data and business logic necessary for your views. (That includes things like SelectLists. Neither your controller nor view should need to know how to create a SelectList for a dropdown.)