为什么 MVC 在 GET 上使用模型状态而不是提供的模型

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

当 MVC 运行 ActionMethod 时,它将填充 ModelState 字典并使用 ModelBinder 构建 ActionMethod 参数(如果有)。它对 GETPOST 都这样做。这是有道理的。

ActionMethod 成功 运行 之后,使用提供的剃刀呈现视图,在我的例子中,它使用了尽可能多的 HtmlHelper 调用。到现在为止,您可能会想,'Yes I know how MVC works'。等一下,我马上就到了。

当我们使用例如@Html.TextFor(m => m.Name) MVC使用可以here的代码来渲染标签。

有趣的部分是在我们发现的文件末尾:

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 使用用户已经提供的值来呈现视图。文档还说明了这种行为,Whosebug 上有几篇文章证实了这一点。但它仅适用于 POST,如在 this thread 上所见,例如

但是,当为 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);
}

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

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

我希望视图显示新生成的 GUID 而不是原始模型的 Id。但是视图显示 IdGET 请求上传递给 actionmethod,因为 ModelState 字典包含一个名为 Id.

的键

我的问题不是关于如何解决这个问题,因为这很简单:

我的问题是: 为什么 GETPOST 的过程相同。在 GET.

上使用填充的 ModelState 而不是提供的 Model 是否有任何有效的用例

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

以航空公司预订应用程序为例,您有一个模型具有 select 出发和到达地点、日期和乘客人数的属性(int 属性),加上过滤结果的集合 属性。 GET 方法签名可能类似于

public ActionResult Search(SearchViewModel model)

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

已禁用 javascript 的(不太聪明的)用户在文本框中输入 "TWO" 并提交表单。您的方法 returns 未填充可用航班集合的视图,因为 ModelState 无效(值 "TWO" 对 int 无效),现在用户看到错误消息说明 字段 Passengers 必须是数字

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