为什么MVC在GET上使用Modelstate而非提供的Model

Ric*_*Net 5 c# asp.net-mvc modelstate razor

当MVC运行时ActionMethod,它将填充ModelState字典并使用a ModelBinder来构建ActionMethod参数(如果有的话).它这样做是两个GETPOST.这是有道理的.

ActionMethod成功已经跑了,视图是使用所提供的剃刀,这在我的情况下,使用尽可能多的呈现HtmlHelper通话成为可能.到现在为止,您可能会想,"我知道MVC是如何工作的".等等,我到了那里.

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

有趣的部分是在我们找到的文件的末尾:

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;
} 
Run Code Online (Sandbox Code Playgroud)

这意味着它Modelstate用于获取提供的值Model.这对于a是有意义的,POST因为当存在验证错误时,您希望MVC使用用户已经提供的值来呈现视图.文档还说明了这种行为,StackOverflow上有几篇帖子证实了这一点.但它只是为说明POST,如能上可以看到这个线程,例如

但是,当为一个视图渲染时,也会使用此代码GET!这对我来说毫无意义.

请考虑以下操作方法:

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);
}
Run Code Online (Sandbox Code Playgroud)

用这个简单的剃​​刀标记:

    @Html.TextBoxFor(m => m.Id)
    @Html.TextBoxFor(m => m.Name)
Run Code Online (Sandbox Code Playgroud)

我希望视图显示新生成的GUID而不是Id原始模型.但是,视图显示Id传递给GET请求的actionmethod,因为ModelState字典包含带有名称的键Id.

我的问题不在于如何解决这个问题,因为这很容易:

  • ActionMethod参数重命名为不同的名称
  • ModelState在返回ActionResult使用之前清除Modelstate.Clear()
  • 替换ModelState字典中的值,根本不提供Model视图.

我的问题是:为什么这个程序为两个相同的GETPOST.是否有任何有效的用例来使用填充在a上ModelState提供ModelGET.

小智 3

DefaultModelBinder区分 GET 和 POST 请求。虽然只有 MVC 团队可以确认他们为何做出该决定,但有一些有效的用例说明为什么ModelState应该在 GET 中使用(与在 POST 中使用的方式相同),因为您也可以向 GET 方法提交表单。

以航空公司预订应用程序为例,其中您有一个模型,其中包含用于选择出发和到达地点、日期和乘客数量(属性int)的属性,以及用于筛选结果的集合属性。GET 方法签名可能如下所示

public ActionResult Search(SearchViewModel model)
Run Code Online (Sandbox Code Playgroud)

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

禁用了 javascript 的(不太聪明的)用户在文本框中输入“TWO”并提交表单。您的方法返回视图,但不填充可用航班的集合,因为ModelState无效(值“TWO”对于 无效int),现在用户会看到一条错误消息,指出字段 Passengers 必须是数字

如果使用模型值而不是ModelState值,则将显示关联的文本框0而不是"Two",从而使错误消息令人困惑(但它0是一个数字! - 我输入的内容发生了什么?)