当MVC运行ActionMethod
时,它将填充ModelState
字典并使用ModelBinder
构建ActionMethod
参数(如果有)。它为GET
和POST
执行此操作。这是有道理的。
成功运行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
。我的问题是:
为什么GET
和POST
的处理方式相同。在ModelState
上使用已填充的Model
上填充的GET
是否有任何有效用例。
答案 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}是一个数字! - 我输入的内容发生了什么?)