为什么MVC在GET上提供的模型上使用Modelstate [英] Why does MVC use the Modelstate over a supplied Model on a GET

查看:81
本文介绍了为什么MVC在GET上提供的模型上使用Modelstate的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当MVC运行ActionMethod时,它将填充ModelState词典并使用ModelBinder来构建ActionMethod参数(如果有).它对GETPOST都执行此操作.这是有道理的.

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.

成功运行ActionMethod后,使用提供的剃刀渲染视图,在我的情况下,该剃刀使用尽可能多的HtmlHelper调用.到目前为止,您可能会想,是的,我知道MVC的工作原理".等等,我要去那里.

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.

当我们使用例如@Html.TextFor(m => m.Name) MVC使用的代码可以在此处呈现标记.

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;
} 

这意味着Modelstate用于获取所提供的Model上的值.这对于POST是有意义的,因为当发生验证错误时,您希望MVC使用用户已经提供的值来呈现视图.该文档还说明了这种行为,StackOverflow上有数篇文章对此进行了确认.但这仅针对POST进行了说明,例如在此线程上可以看到

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

但是,为GET渲染视图时也使用此代码!这对我完全没有意义.

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

请考虑以下操作方法:

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)

我希望该视图显示新生成的GUID而不是原始模型的Id.但是,该视图显示了Id传递给GET请求的操作方法的原因,因为ModelState词典包含名称为Id的键.

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:

  • ActionMethod参数重命名为其他内容
  • 在使用Modelstate.Clear()
  • 返回ActionResult之前先清除ModelState
  • 替换ModelState词典中的值,根本不向视图提供Model.
  • 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.

我的问题是: 为什么GETPOST的处理过程相同.在GET上提供的Model上使用填充的ModelState是否有任何有效的用例.

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.

推荐答案

DefaultModelBinder不会区分GET和POST请求.尽管只有MVC团队可以确认为什么要​​做出此决定,但是在有效的用例中,为什么应该在GET中使用ModelState(与在POST中使用的方式相同),因为您还可以向GET方法提交表单

The DefaultModelBinder does not make a distinction between GET and POST requests. While only the MVC team can confirm why they made that decision, there are valid use cases why ModelState should be used in a GET (in the same way its used in a POST) since you can also submit a form to a GET method.

以一个航空公司预订应用程序为例,您拥有一个模型,该模型具有用于选择出发和到达位置,日期和乘客人数的属性(int属性),以及用于过滤结果的集合属性. GET方法签名可能看起来像

Take for example an airline booking app, where you have a model with properties to select departure and arrival locations, a date, and the number of passengers (an int property), plus a collection property for the filtered results. The GET method signature might look like

public ActionResult Search(SearchViewModel model)

该视图包含一个使方法返回GET的,并包含一个用于显示乘客人数的文本框.

The view includes a that makes a GET back to the method and includes a textbox for the number of passengers.

已禁用javascript的用户(不是太聪明)在文本框中输入两个"并提交表单.您的方法返回视图而不填充可用航班的集合,因为ModelState无效(值int无效),现在用户看到一条错误消息,说明一个数字.

A (not too bright) user who has disabled javascript enters "TWO" in the textbox and submits the form. Your method returns the view without populating the collection of available flights because ModelState is invalid (the value "TWO" is not valid for an int) and now the user sees an error message stating The field Passengers must be a number.

如果使用模型值而不是ModelState值,则关联的文本框将显示0而不是"Two",从而使错误消息造成混淆(但是0是数字!-以及我输入的内容发生了什么?)

If the model value was used rather that the ModelState value, then the associated textbox would be displaying 0 instead of "Two", making the error message confusing (but 0 is a number! - and what happened to what I entered?)

这篇关于为什么MVC在GET上提供的模型上使用Modelstate的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆