Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is a value that I update in my model inside an MVC3 controller not rendered on the client?

I have a controller action UpdateCustomer(CustomerDto customer) that returns a PartialViewResult with a model that is also a CustomerDto:

[HttpPost]
public PartialViewResult UpdateCustomer(CustomerDto customer)
{
    CustomerDto updatedCustomer = _customerService.UpdateCustomer(customer);
    updatedCustomer.Name = "NotThePostedName";
    return PartialView("CustomerData", updatedCustomer);
}

In my view, I have the following line:

@Html.TextBoxFor(model => model.Name)

So far, so good. In my view I do an asynchronous post to this action method, the model binder does its work and I can update a customer in the database. Then I want to render the updated customer to the client. For example, I'd like to change the customer name in my controller. However, what gets rendered is always the properties from the posted customer, not the properties from updatedCustomer.

I decided to include the MVC3 source code in my project to see what really happens. It appears to be a feature (bug?) of MVC3 that it always takes the value from ViewData.ModelState instead of the value from ViewData.Model.

This happens at lines 366-367 of System.Web.Mvc.Html.InputExtensions:

string attemptedValue =
    (string) htmlHelper.GetModelStateValue(fullName, typeof(string));
tagBuilder.MergeAttribute("value",
    attemptedValue ?? ((useViewData)
        ? htmlHelper.EvalString(fullName)
        : valueParameter), isExplicitValue);

As you can see, attemptedValue comes from ModelState. It contains the old value for CustomerDto.Name (the value that was posted to the controller action).

If this is a feature, why does it work this way? And is there a way to work around it? I would expect that if I update my model, the update gets rendered, not the old value I posted.

like image 836
Ronald Wildenberg Avatar asked Apr 15 '11 10:04

Ronald Wildenberg


1 Answers

Well yes it's a feature (ModelState is always checked before actual Model), you can clear the ModelState, or update just the value you need:

ModelState["Name"].Value = updatedCustomer.Name;
like image 143
tpeczek Avatar answered Sep 29 '22 07:09

tpeczek