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 *开发者_StackOverflow/
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?
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:
- ViewData.ModelState dictionary entry
- Model property (if a strongly typed view. This property is a shortcut to View.ViewData.Model)
- 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.
The values are stored in ModelState
.
This should do what you want:
ModelState.SetModelValue("ProductName", "The new value");
I wouldn't suggest doing that though... the correct method would be to follow the PRG (Post/Redirect/Get) pattern.
HTHs,
Charles
EDIT: Updated to reflect the better was of setting the ModelState
value as found by @Gary
This will trigger the model to re-evaluate under simple conditions:
ModelState.Clear();
model.Property = "new value";
TryValidateModel(model);
Perform ModelState.Clear() before you change the model.
...
ModelState.Clear()
dbProduct.ProductName = product.ProductName;
dbProduct.UnitPrice = product.UnitPrice;
...
精彩评论