Thorsten Westheider
Thorsten Westheider

Reputation: 10932

How to create a complex view model in ASP.NET MVC?

Creating and updating a complex view model is what I struggle with most of the time when I'm working on a web project.

For instance, I got a PageViewModel that takes a background image URL and a page title to pass to _Layout.cshtml, so

@model WebApplication.ViewModels.PageViewModel

<body [email protected]>
   ...
</body

As for every other view model I now got 2 options:

  1. Derive from PageViewModel
  2. Create a property on PageViewModel to hold the specific view model (composition over inheritance etc.)

For obvious reasons I'm more inclined towards option 2. In any case, for GET actions I now need to initialise all the properties from PageViewModel as well as the properties from the view model I actually need for a particular action, e.g.

public PageViewModel
{
    public string BackgroundImageUrl { get; set; }
    public ContactViewModel Contact { get; set; }
}

is created like

public IActionResult Contact(int contactId)
{
   ...
   var viewmodel = new PageViewModel
   {
      BackgroundImageUrl = ...,
      ContactViewModel = new 
      {
         ...
      }
   }
}

which to me is a recipe for disaster.

Things get even worse on POST, because ideally I will post only those fields that are relevant to the action in question, that is

public IActionResult Contact(ContactViewModel viewmodel)
{
   if (ModelState.IsValid)
   {
      ... (this is the easy case)
      return RedirectToAction(...)
   }

   ... (now we have a problem)
}

If anything goes wrong in the POST action I need to rebuild the entire view model graph, which is not too bad for the above example but in a real world application this gets extremely messy very fast (just think of populating drop down lists with data from a store). Controller actions are supposed to be lean, aren't they? It doesn't feel right to make the view models responsible for retrieving their own data either, so probably I should come up with a view model factory. That in turn will produce a plethora of factories, one for each view model which, again, will get messy.

I'm wondering if there is a better approach.

Upvotes: 1

Views: 1249

Answers (1)

Darin Dimitrov
Darin Dimitrov

Reputation: 1038930

One possibility to consider is to use a child action responsible for some portion of the layout.

So for example you could have the following child action which will be responsible for populating the background image URL:

[ChildActionOnly]
public ActionResult BackgroundImage() 
{
    var model = new MyViewModel
    {
        BackgroundImageUrl = ...
    };
    return PartialView(model);
}

and then have a corresponding partial view:

@model MyViewModel

<img src="@Model.BackgroundImageUrl" alt="" />

which can be included in your main Layout (which in this case doesn't need a view model because the different portions of it will be assembled from the child actions):

<body>
    @Html.Action("BackgroundImage", "SomeController")
    ...
</body>

Using this approach the main action that is responsible for rendering the view doesn't need to know and assemble a complex view model. It will focus only on its specific view model.

Upvotes: 2

Related Questions