Updating Posted Form Values on Postback with MVC – Fixing “Cached” Values

While working on a project I encountered a strange issue.  I created a simple registration form that posted back to my controller method, which received a view model as a parameter.  In my method I needed to update the values on this View Model before passing it back to the user through the same View.  However, this is where I encountered “strange” results.  Despite the correct data binding, correct code updating the model values, and the correct model being passed into the view, front-end users still received the old form values they initially posted.

This was initially puzzling, because I could see that the model I was passing in was correctly updated.   At first I assumed it was some kind of caching issue and tried a number of options, but to no avail.  Eventually I figured out the problem was coming from the Razor Helper I was using – specifically the EditorFor method (although this applies to any Razor helper method).

Let’s take a closer look.  Below is a simple registration view:

@model  posting.Controllers.Guest
 
<h2>Register</h2>
 
<p>Welcome...</p>
 
@using (Html.BeginForm())
{
    <table>
        <tr>
            <td>
                @Html.LabelFor(g => g.FirstName)
            </td>
            <td>
                @Html.EditorFor(g => g.FirstName)
            </td>
        </tr>
        <tr>
            <td>
                @Html.LabelFor(g => g.LastName)
            </td>
            <td>
                @Html.EditorFor(g => g.LastName)
            </td>
        </tr>
        <tr>
            <td>
                @Html.LabelFor(g => g.Highlight)
            </td>
            <td>
                @Html.EditorFor(g => g.Highlight)
            </td>
        </tr>
    </table>
    <input type="submit" />
}

I have set up two simple controller methods to demonstrate this problem.

public ActionResult Register()
{
      return View();
}
 
[HttpPost]
public ActionResult Register(Guest guest)
{
     guest.FirstName = "Bobby";
            
     return View(guest);
}

The first register method is a Get request that returns a simple sign up form with a first name and last name. The second method is the Post version of the first method, meaning the values our user enters into the form will get mapped to our Guest view model. For demonstration purposes, I am changing all users’ names to Bobby. However, if you run this and fill out the form, you will notice the name never comes back as Bobby – it always comes back as whatever the user entered.

The reason for this is the EditorFor helper method. These helper methods retrieve their data from ModelState first, then from the model object that is passed in.  ModelState is basically metadata about the current model assigned by the MVC Model Binder when a request is mapped to a controller.  So if the ModelState already has values mapped by the MVC Model Binder, Razor Helpers will use those. The solution for this is simple.

[HttpPost]
public ActionResult Register(Guest guest)
{
    ModelState.Remove("FirstName");
    guest.FirstName = "Bobby"; 
            
    return View(guest);
}

That’s literally all we have to do – this will remove the FirstName property value set by the default MVC Model Binder and allow our own code to write a new value. You can also clear out the entire ModelState at once, as seen below:

[HttpPost]
public ActionResult Register(Guest guest)
{
      ModelState.Clear();
      guest.FirstName = "Bobby";
            
      return View(guest);
}

This is a really simple issue but can be very frustrating if you don’t know what’s going on.

Hope this helps….

No Comments

Comments Closed