简体   繁体   中英

Changing ViewModel properties in POST action

I have this POST action:

[HttpPost]
public ActionResult GetReport(GetReportModel model)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }

    return View("GetReport", new GetReportModel()
       { 
          Identifier = "test", 
          Permission = true 
       });
}

When I POST my form, and this action is executed there are no changes in the resulting View. I mean, the TextBox for Identifier doesn't have the "test" string value I set in the action. But if I clear ModelState , the View will show the new value:

[HttpPost]
public ActionResult GetReport(GetReportModel model)
{
    if (!ModelState.IsValid)
    {
        return View();
    }

    ModelState.Remove("Identifier");
    ModelState.Remove("Permission");

    return View("GetReport", new GetReportModel() 
       {
          Identifier = "test", 
          Permission = true 
       });
}

I don't understand why this happens? And why does everyone return their model to the View if it has an invalid model state? For example, the default project template from Microsoft has this code:

public ActionResult Login(LoginModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        return RedirectToLocal(returnUrl);
    }
    // Why do they pass the model object to the view
    // if it will be there anyway from post data?
    return View(model);
}

To answer your second question first: The model object won't be there if you don't pass it to View() . The Model property of the view will be null . Which means something as simple as this in your view:

@Model.Identifier

... will fail with a NullReferenceException . Which is one reason why we pass the model back into the view. That the ModelState is invalid doesn't matter (and it will be given to the view even if you don't pass a model) - actually, we want that invalid state, because it's what allows us to give the user helpful error messages.

But there's actually a good point in your first question, which few MVC programmers seem to realize, because it's transparent in the most common use case:

The reason eg HtmlHelper -created input fields and validation will still work when calling View() without the model from your POST method is this: If they can get away with it, the helper methods don't use the model's properties at all. They'll try to find the value for eg <input> s in this order:

  • ModelState["Identifier"].Value
  • ViewData (only in certain cases)
  • the model's value.

The first one that isn't null wins.

In other words, the helper will only look at your model's Identifier property if ModelState["Identifier"] is null (or its Value is null).

That also means that changing the properties on your model as you do in the first example will not change the rendered field's contents. If the user entered "no, please don't test", even if you send back a model with "test", the text in the input field will still be "no, please don't test".

So yes, if you need to set new values for your inputs as response to POST, you'll need to remove their state from the ModelState . Or not use the HTML helpers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM