ASP.Net MVC - GET/POST 具有不同模型时的 ModelState.AddModelError

Posted

技术标签:

【中文标题】ASP.Net MVC - GET/POST 具有不同模型时的 ModelState.AddModelError【英文标题】:ASP.Net MVC - ModelState.AddModelError when GET/POST have different models 【发布时间】:2015-08-15 11:06:20 【问题描述】:

我有一个用例,我在控制器中为 GET 和 POST 操作使用了不同的模型。这对我的观点很有效,因为大部分数据都进入了标签。 GET 方法的模型包含 10 个属性,而 POST 方法的模型只需要 3 个。

这个 GET 视图呈现一个表单,它只需要其中的 3 个属性,而不是全部 10 个。因此,POST 方法的模型接受仅包含这 3 个属性的模型类。因此,ASP.Net MVC 模型绑定器仅使用这 3 个必要属性填充我的 POST 方法上的模型类参数,一切都很好。

问题来了:当我在POST方法中遇到一些业务规则违规,想使用ModelState.AddModelError,重新显示原来的视图时,我已经没有这7个属性了未发布,因为它们不是表单的一部分,也不是此方法作为其参数的模型类的一部分。

目前,我正在调用构建器以返回 POST 方法的模型类实例,并让 GET 方法本身委托给同一个构建器。因此,在这些情况下,当 POST 方法中存在某些业务规则违规时,我会返回一个 View("OriginalGetView", originalGetModel)。在这种情况下,如何在 POST 方法中使用 ModelState.AddModelError,如果我想使用完全不同的模型类将自定义消息发送回视图?

考虑到它们的需求是如此不同,对 GET 和 POST 方法使用相同的模型类似乎太懒了。这里的最佳做法是什么?我看到很多人建议对这两种方法使用相同的模型,并从隐藏的表单字段中返回所有字段,但这在大多数情况下似乎是浪费带宽,而且感觉很难看当我已经拥有“VendorId”时,将“VendorName”之类的内容发送回服务器。

【问题讨论】:

【参考方案1】:

我可能误解了您要做什么,但请确保您不是一分钱一分货的傻瓜。我看到您可能只想发布标识符,而不必发布描述符。但听起来您必须在发布后重新显示视图......如果是这样,如果您发布与 get 中相同的模型,您就可以访问模型属性。如果您只发布标识符,则必须花时间重新访问数据库以使用供应商 ID 获取描述值(即您描述的供应商名称)?那不也是额外的处理吗?就像我说的那样,我可能会误解您的帖子,但是为了保持一致性,使用相同的视图模型来获取和发布您的视图对我来说最有意义。

【讨论】:

对,但这意味着我必须将描述值嵌入隐藏字段中,然后将它们与标识符一起发送到线路上。我不介意在云中使用计算资源来代替慢速无线网络或动力不足的移动设备的负担。此应用程序需要大规模的最佳性能,因此可以在云中轻松补偿客户端的节省。你是对的;我们可以每次只往返这些数据,但 99% 的时间,这在 POST 上是浪费的。【参考方案2】:

我认为隐藏输入可能是最好的解决方案,即使在 2g 上,您也不应该创建任何延迟,除非您的模型属性的值是长字符串或加密或 xml。

因此,您的 .cshtml 将包含当前未包含在表单中的 4 个属性:

<form>
    @Html.HiddenFor(m => m.Property1)
    @Html.HiddenFor(m => m.Property2)
    @Html.HiddenFor(m => m.Property3)
    @Html.HiddenFor(m => m.Property4)

但您也可以从原始发布的模型中获取模型状态错误,并在您的响应模型中重新创建 ModelError 状态以绕过使用隐藏输入。

我刚刚找到本指南(不是绿色复选标记的答案,而是最高的答案:ASP.NET MVC - How to Preserve ModelState Errors Across RedirectToAction?

注意:如果您需要将模型属性从模型复制到另一个模型(相同类型或不同类型),请以更简洁的方式查看 AutoMapper。

【讨论】:

这是代码当前所做的(您的“或”选项)。这就是我使用构建器模式的原因。我更新了我的帖子(因为我看到我在同一个句子中不小心使用了 GET 两次。其中一个应该说 POST)。我的问题得到纠正。感谢您提供示例代码;这是对我已经在做的事情的简要概述。 好的,这个解决方案没有任何问题,它不是懒惰的,也不是你在问题中所说的“浪费带宽”。不需要有两个模型,您没有使用两个模型保存任何“带宽”,但是您正在添加额外的代码,以及通过具有第二个模型的代码文件,该模型具有所有相同的属性并与您的单个模型使用相同的视图模型设置。 没有节省任何带宽?真的吗?我保存的大部分内容是字符串字段,只有在违反某种业务规则时才需要在 POST 方法中使用,即使这样也仅用于显示。 99% 的情况下,POST 会成功,并且用户会看到结果视图。所以,你是说在每个 POST 上发送 7 个描述性字符串字段,当它们与操作无关时,不是浪费吗?如果不是,那是什么? 感谢您分析此案例,并感谢您的深思熟虑。我希望不是每个人都这样想,不费心去节约资源;难怪我镇上的 VZW 塔 24/7 都饱和了。曾经有一段时间,开发人员和供应商都关心节约。看看 facebook——他们有超过 14.4 亿的用户。你认为他们浪费带宽吗?代价将是巨大的。 我改了答案,替代隐藏输入,你可以在你的HttpPost中重新创建模型错误状态【参考方案3】:

也许这有助于您尝试实现的目标 - “模型”级别错误 - 不需要附加到特定字段/属性 - 但可以显示在全局区域中。

https://***.com/a/53716648/10257093

【讨论】:

以上是关于ASP.Net MVC - GET/POST 具有不同模型时的 ModelState.AddModelError的主要内容,如果未能解决你的问题,请参考以下文章

asp.net mvc3.0中视图引擎razor和ASPX可以交互使用吗

为啥 Asp.net MVC 不能区分具有不同参数的两个动作?

ASP.NET MVC 3:具有继承/多态性的 DefaultModelBinder

iis 中具有多个子域的 asp.net mvc 站点

如何创建具有所需验证的 ASP.Net MVC DropDownList

具有捆绑和缩小功能的 ASP.NET MVC 4 应用程序,为啥在调试模式下启用缩小?