为什么MVC在GET上提供的模型上使用Modelstate [英] Why does MVC use the Modelstate over a supplied Model on a GET
问题描述
当MVC运行ActionMethod
时,它将填充ModelState
词典并使用ModelBinder
来构建ActionMethod
参数(如果有).它对GET
和POST
都执行此操作.这是有道理的.
When MVC runs an ActionMethod
it will populate the ModelState
dictionary and uses a ModelBinder
to build the ActionMethod
parameter(s) if any. It does this for both GET
and POST
. Which makes sense.
成功运行ActionMethod
后,使用提供的剃刀渲染视图,在我的情况下,该剃刀使用尽可能多的HtmlHelper
调用.到目前为止,您可能会想,是的,我知道MVC的工作原理".等等,我要去那里.
After the ActionMethod
successfully has been ran, the view is rendered using the razor supplied, which in my case uses as much HtmlHelper
calls as possible. Until now, you might think, 'Yes I know how MVC works'. Hold on, I'm getting there.
当我们使用例如@Html.TextFor(m => m.Name)
MVC使用的代码可以在此处呈现标记.
When we use e.g. @Html.TextFor(m => m.Name)
MVC uses the code that can be here to render the tag.
有趣的部分是我们在文件末尾的位置:
The interesting part is at the end of the file where we find:
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
进行了说明,例如在此线程上可以看到
What this means is that the Modelstate
is used to get a value over a supplied Model
. And this makes sense for a POST
because when there are validation errors you want MVC to render the view with the values already supplied by the user. The documentation also states this behavior and there are several posts here on StackOverflow confirming this. But it is stated only for POST
, as can be seen on this thread for example
但是,为GET
渲染视图时也使用此代码!这对我完全没有意义.
However this code is also used when a view is rendered for a GET
! And this makes no sense at all to me.
请考虑以下操作方法:
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);
}
使用此简单的剃刀标记:
with this simple razor markup:
@Html.TextBoxFor(m => m.Id)
@Html.TextBoxFor(m => m.Name)
我希望该视图显示新生成的GUID
而不是原始模型的Id
.但是,该视图显示了Id
传递给GET
请求的操作方法的原因,因为ModelState
词典包含名称为Id
的键.
I would expect the view to show the newly generated GUID
instead of the Id
of the original model. However the view shows the Id
passed to the actionmethod on the GET
request because the ModelState
dictionary contains a key with the name Id
.
我的问题不是关于如何解决这个问题,因为那很容易:
My question is not on how to solve this, because that is fairly easy:
- 将
ActionMethod
参数重命名为其他内容 - 在使用
Modelstate.Clear()
返回 - 替换
ModelState
词典中的值,根本不向视图提供Model
.
ActionResult
之前先清除ModelState
- rename the
ActionMethod
parameter to something different - Clear the
ModelState
before returning theActionResult
usingModelstate.Clear()
- Replace the value in the
ModelState
dictionary and don't supply aModel
to the view at all.
我的问题是:
为什么GET
和POST
的处理过程相同.在GET
上提供的Model
上使用填充的ModelState
是否有任何有效的用例.
My question is:
Why is this proces the same for both GET
and POST
. Is there any valid use case for using the populated ModelState
over the supplied Model
on a GET
.
推荐答案
DefaultModelBinder
不会区分GET和POST请求.尽管只有MVC团队可以确认为什么要做出此决定,但是在有效的用例中,为什么应该在GET中使用ModelState
(与在POST中使用的方式相同),因为您还可以向GET方法提交表单
The DefaultModelBinder
does not make a distinction between GET and POST requests. While only the MVC team can confirm why they made that decision, there are valid use cases why ModelState
should be used in a GET (in the same way its used in a POST) since you can also submit a form to a GET method.
以一个航空公司预订应用程序为例,您拥有一个模型,该模型具有用于选择出发和到达位置,日期和乘客人数的属性(int
属性),以及用于过滤结果的集合属性. GET方法签名可能看起来像
Take for example an airline booking app, where you have a model with properties to select departure and arrival locations, a date, and the number of passengers (an int
property), plus a collection property for the filtered results. The GET method signature might look like
public ActionResult Search(SearchViewModel model)
该视图包含一个使方法返回GET的,并包含一个用于显示乘客人数的文本框.
The view includes a that makes a GET back to the method and includes a textbox for the number of passengers.
已禁用javascript的用户(不是太聪明)在文本框中输入两个"并提交表单.您的方法返回视图而不填充可用航班的集合,因为ModelState
无效(值
A (not too bright) user who has disabled javascript enters "TWO" in the textbox and submits the form. Your method returns the view without populating the collection of available flights because ModelState
is invalid (the value "TWO" is not valid for an int
) and now the user sees an error message stating The field Passengers must be a number.
如果使用模型值而不是ModelState
值,则关联的文本框将显示0
而不是"Two"
,从而使错误消息造成混淆(但是0
是数字!-以及我输入的内容发生了什么?)
If the model value was used rather that the ModelState
value, then the associated textbox would be displaying 0
instead of "Two"
, making the error message confusing (but 0
is a number! - and what happened to what I entered?)
这篇关于为什么MVC在GET上提供的模型上使用Modelstate的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!