Home Why does MVC use the Modelstate over a supplied Model on a GET
Reply: 0

Why does MVC use the Modelstate over a supplied Model on a GET

user3388
1#
user3388 Published in April 24, 2018, 6:32 am

When MVC runs an ActionMethod it will populate the ModelState dictionary and uses a ModelBinder to build the ActionMethod parameter(s) if any. It does this for both GET and POST. Which makes sense.

After the ActionMethod successfully has been ran, the view is rendered using the razor supplied, which in my case uses as much HtmlHelper calls as possible. Until now, you might think, 'Yes I know how MVC works'. Hold on, I'm getting there.

When we use e.g. @Html.TextFor(m => m.Name) MVC uses the code that can be here to render the tag.

The interesting part is at the end of the file where we find:

switch (inputType)
{
    case InputType.CheckBox:
        // ... removed for brevity
    case InputType.Radio:
    // ... removed for brevity
    case InputType.Password:
    // ... removed for brevity
    default:
        string attemptedValue = 
               (string)htmlHelper.GetModelStateValue(fullName, typeof(string));
        tagBuilder.MergeAttribute("value", attemptedValue ?? 
               ((useViewData) 
                  ? htmlHelper.EvalString(fullName, format) 
                  : valueParameter), isExplicitValue);
        break;
} 

What this means is that the Modelstate is used to get a value over a supplied Model. And this makes sense for a POST because when there are validation errors you want MVC to render the view with the values already supplied by the user. The documentation also states this behavior and there are several posts here on StackOverflow confirming this. But it is stated only for POST, as can be seen on this thread for example

However this code is also used when a view is rendered for a GET! And this makes no sense at all to me.

Consider the following action method:

public ActionResult GetCopy(Guid id)
{
    var originalModel = this.repository.GetById(id);
    var copiedModel = new SomeModel
    {
        Id = Guid.NewGuid(),
        Name = originalModel.Name,
    };

    return this.View(copiedModel);
}

with this simple razor markup:

    @Html.TextBoxFor(m => m.Id)
    @Html.TextBoxFor(m => m.Name)

I would expect the view to show the newly generated GUID instead of the Id of the original model. However the view shows the Id passed to the actionmethod on the GET request because the ModelState dictionary contains a key with the name Id.

My question is not on how to solve this, because that is fairly easy:

  • rename the ActionMethod parameter to something different
  • Clear the ModelState before returning the ActionResult using Modelstate.Clear()
  • Replace the value in the ModelState dictionary and don't supply a Model to the view at all.

My question is: Why is this proces the same for both GET and POST. Is there any valid use case for using the populated ModelState over the supplied Model on a GET.

You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.379351 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO