Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to modify posted form data within controller action before sending to view?

Tags:

asp.net-mvc

I want to render the same view after a successful action (rather than use RedirectToAction), but I need to modify the model data that is rendered to that view. The following is a contrived example that demonstrates two methods that that do not work:

    [AcceptVerbs("POST")]
    public ActionResult EditProduct(int id, [Bind(Include="UnitPrice, ProductName")]Product product) {
        NORTHWNDEntities entities = new NORTHWNDEntities();

        if (ModelState.IsValid) {
            var dbProduct = entities.ProductSet.First(p => p.ProductID == id);
            dbProduct.ProductName = product.ProductName;
            dbProduct.UnitPrice = product.UnitPrice;
            entities.SaveChanges();
        }

        /* Neither of these work */
        product.ProductName = "This has no effect";
        ViewData["ProductName"] = "This has no effect either";

        return View(product);
    }

Does anyone know what the correct method is for accomplishing this?

like image 558
gxclarke Avatar asked Apr 21 '10 21:04

gxclarke


1 Answers

After researching this further, I have an explanation why the following code has no effect in the Action:

product.ProductName = "This has no effect";
ViewData["ProductName"] = "This has no effect either";

My View uses HTML Helpers:

<% Html.EditorFor(x => x.ProductName);

HTML Helpers uses the following order precedence when attempting lookup of the key:

  1. ViewData.ModelState dictionary entry
  2. Model property (if a strongly typed view. This property is a shortcut to View.ViewData.Model)
  3. ViewData dictionary entry

For HTTP Post Actions, ModelState is always populated, so modifying the Model (product.ProductName) or ViewData directly (ViewData["ProductName"]) has no effect.

If you do need to modify ModelState directly, the syntax to do so is:

ModelState.SetModelValue("ProductName", new ValueProviderResult("Your new value", "", CultureInfo.InvariantCulture));

Or, to clear the ModelState value:

ModelState.SetModelValue("ProductName", null);

You can create an extension method to simplify the syntax:

public static class ModelStateDictionaryExtensions {
    public static void SetModelValue(this ModelStateDictionary modelState, string key, object rawValue) {
        modelState.SetModelValue(key, new ValueProviderResult(rawValue, String.Empty, CultureInfo.InvariantCulture));
    }
}

Then you can simply write:

ModelState.SetModelValue("ProductName", "Your new value");

For more details, see Consumption of Data in MVC2 Views.

like image 196
gxclarke Avatar answered Oct 11 '22 12:10

gxclarke