【发布时间】:2018-06-20 15:04:17
【问题描述】:
当 MVC 运行 ActionMethod 时,它将填充 ModelState 字典并使用 ModelBinder 来构建 ActionMethod 参数(如果有)。它对GET 和POST 都执行此操作。这是有道理的。
ActionMethod 成功运行后,使用提供的剃须刀呈现视图,在我的例子中,它使用尽可能多的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 传递给 GET 请求上的操作方法,因为 ModelState 字典包含名称为 Id 的键。
我的问题不是如何解决这个问题,因为这很容易:
- 将
ActionMethod参数重命名为不同的名称 - 使用
Modelstate.Clear()在返回ActionResult之前清除ModelState - 替换
ModelState字典中的值,并且根本不向视图提供Model。
我的问题是:
为什么GET 和POST 的过程相同。在GET 上使用填充的ModelState 而不是提供的Model 是否有任何有效的用例。
【问题讨论】:
-
DefaultModelBinder不区分 GET 或 POST。但是为什么你认为行为应该不同呢?如果我向一个方法发出请求并传递一个值,那么我希望我传递的值被使用,而不是一些完全不同的值 -
@StephenMuecke 一般来说,我希望如果我将一个对象传递给一个方法,它将被使用,而不是来自环境上下文的数据。所以
this.View(model)在我看来会使用model的数据。 -
而且我希望如果我有(比如说)一个制作 GET 的表单(比如说传递一些用于过滤记录的“搜索”值),那么这些值将再次返回。 (我有点不确定如何处理这个问题 - 投票,因为它写得很好,研究得很好,和/或投票关闭它,因为它征求意见:)
-
问题是是否有任何有效的用例
-
我在之前的评论中给了你我的看法:)
标签: c# asp.net-mvc razor modelstate