代码之家  ›  专栏  ›  技术社区  ›  Ric .Net

为什么MVC在GET上对提供的模型使用Modelstate

  •  5
  • Ric .Net  · 技术社区  · 7 年前

    当MVC运行 ActionMethod 它将填充 ModelState 字典并使用 ModelBinder 要构建 ActionMethod操作方法 参数(如有)。这对双方都有好处 GET POST . 这很有道理。

    ActionMethod操作方法 已成功运行,使用提供的razor渲染视图,在我的情况下,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 . 这对于 发布 因为当出现验证错误时,您希望MVC使用用户已经提供的值渲染视图。文档还说明了这种行为,StackOverflow上有几个帖子证实了这一点。但仅针对 发布 ,如图所示 this thread 例如

    但是,当为渲染视图时,也会使用此代码 获取 ! 这对我来说毫无意义。

    考虑以下操作方法:

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

    使用此简单的razor标记:

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

    我希望视图显示新生成的 GUID 而不是 Id 原始模型的。然而,视图显示 身份证件 传递给上的actionmethod 获取 请求,因为 模型状态 字典包含一个名为 身份证件 .

    我的问题不是如何解决这个问题,因为这相当容易:

    • 重命名 ActionMethod操作方法 参数设置为其他参数
    • 清除 模型状态 在返回之前 ActionResult 使用 Modelstate.Clear()
    • 替换中的值 模型状态 字典,不提供 模型 对视图而言。

    我的问题是: 为什么这两个过程都是一样的 获取 发布 . 使用填充的 模型状态 超过所提供的 模型 在上 获取 .

    1 回复  |  直到 7 年前
        1
  •  3
  •   user3559349 user3559349    7 年前

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

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

    public ActionResult Search(SearchViewModel model)
    

    该视图包括一个返回方法的文本框,还包括一个用于显示乘客人数的文本框。

    禁用javascript的用户(不太聪明)在文本框中输入“2”并提交表单。您的方法返回视图而不填充可用航班的集合,因为 模型状态 无效(值“2”对于 内景 )现在,用户看到一条错误消息 现场乘客必须是数字 .

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