Click here to Skip to main content
15,867,835 members
Articles / Web Development / HTML
Tip/Trick

Restoring View Model State

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
24 Feb 2016CPOL2 min read 12.3K   46   9   5
Simple pattern which I use to solve view model filling problem

Introduction

Today, I want to share with you a pattern which I use in classic ASP.NET MVC web sites. It solves the problem of filling model* properties that won't be sent with http request (e.g. select items). Let's take a closer look.

Image 1

Most of the model properties could be divided into two groups:

  • Domain properties that characterize model
  • Additional properties that describes domain properties
C#
public class Account
{
    // Domain property
    public int CountryId { get; set; }

    // Additional property
    public IEnumerable<KeyValuePair<int, string>> Countries { get; set; }
}

Domain properties do not require extra logic, they come with http response and we send them within http request. Additional properties, on the contrary, cause a problem because they can't be sent along with domain properties. Additional properties are not the part of the domain model and could be large. They do not come to application with request and so these properties are empty. As a result, we can't validate domain properties using additional properties (like to check if selected Country is one of available Countries). When model has additional properties, they have to be filled during processing form request.

So, every time we create a model, we need to fill additional properties. A simple solution is to reside filling logic in controller. But doing so, we receive a code duplication - we have filling logic where we render view and we have it in action that handles form request. Clearly makes sense to extract filling logic into separate class, whose responsibility would be to populate additional properties.

C#
public class AccountFiller : IViewModelFiller<Account>
{
    public void Fill(Account model) {
        model.Countries = Countries.GetAvailable();
    }
}

As previously, we're going to fill model in two places - in controller, when we create model, and in model binder, when we bind form values to model. In model binder, we fill model before validation. So we can use additional properties during validation (using FluentValidation).

C#
// ...somewhere in controller
public  ActionResult Account() {
    var account = new Account { CountryId = 1 };

    _accountFiller.Fill(account);

    return View(account);
}

public class AccountModelBinder : DefaultModelBinder
{
    private readonly IViewModelFiller<Account> _filler;

    public AccountModelBinder(IViewModelFiller<Account> filler) {
        _filler = filler;
    }

    protected override void OnModelUpdated(ControllerContext controllerContext, 
        ModelBindingContext bindingContext) {
        var model = (Account)bindingContext.Model;

        _filler.Fill(model);
       
        base.OnModelUpdated(controllerContext, bindingContext);
    }
}

This pattern works better when DI and FluentValidation are being used. It reduces code duplication and helps to build less coupled, easy to extend testable architecture of request handling pipeline.

* Hereinafter, when I say model, I actually mean view model. The question of applying view models is beyond the scope of this article and won't be discussed here.

This article was originally posted at http://www.wurdum.com

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Ukraine Ukraine
Passionate .Net developer, geek

Comments and Discussions

 
QuestionSample project Pin
Ehsan Sajjad23-Feb-16 21:02
professionalEhsan Sajjad23-Feb-16 21:02 
AnswerRe: Sample project Pin
Pavel Rytikov23-Feb-16 22:59
Pavel Rytikov23-Feb-16 22:59 
GeneralRe: Sample project Pin
Pete O'Hanlon24-Feb-16 2:13
subeditorPete O'Hanlon24-Feb-16 2:13 
GeneralRe: Sample project Pin
Pavel Rytikov24-Feb-16 2:28
Pavel Rytikov24-Feb-16 2:28 
GeneralRe: Sample project Pin
Pete O'Hanlon24-Feb-16 2:30
subeditorPete O'Hanlon24-Feb-16 2:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.