为什么MVC在GET

时间:2018-01-11 10:09:25

标签: c# asp.net-mvc razor modelstate

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

成功运行ActionMethod后,使用提供的razor呈现视图,在我的情况下使用尽可能多的HtmlHelper调用。到目前为止,你可能会想,“是的,我知道MVC是如何工作的”。等一下,我到了那儿。

当我们使用例如@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使用用户已经提供的值来呈现视图。文档还说明了这种行为,StackOverflow上有几篇帖子证实了这一点。但仅针对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。但是,该视图会在Id请求中显示传递给actionmethod的GET,因为ModelState字典包含名为Id的密钥。

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

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

我的问题是: 为什么GETPOST的处理方式相同。在ModelState上使用已填充的Model上填充的GET是否有任何有效用例。

1 个答案:

答案 0 :(得分:3)

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

以航空公司预订应用程序为例,您可以在其中找到具有属性的模型,以选择出发和到达地点,日期和乘客数量(int属性),以及过滤后的收集属性结果。 GET方法签名可能看起来像

public ActionResult Search(SearchViewModel model)

该视图包含一个GET回到该方法,并包含一个乘客数量的文本框。

已禁用javascript的(不太亮)用户进入" TWO"在文本框中并提交表单。您的方法返回视图而不填充可用航班的集合,因为ModelState无效(值" TWO"对int无效),现在用户看到错误消息说明字段乘客必须是一个号码

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