Reputation: 10932
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:
PageViewModel
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
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