【问题标题】:How does the framework know that `ModelState.IsValid` must be true in HTTPGET but false in HTTPPOST when the form fields are invalid?当表单字段无效时,框架如何知道 `ModelState.IsValid` 在 HTTPGET 中必须为真,但在 HTTPPOST 中必须为假?
【发布时间】:2016-10-17 08:39:29
【问题描述】:

考虑一个简单的数据模型Student.cs如下,

class Student
{
    [Required(ErrorMessage="Please enter your name.")]   
    public string Name {get;set;}

    // other properties go here
}

一个表单视图registration.cshtml如下,

<form asp-action="Registration" method="Post">
<p>ModelState.IsVali is @ViewBag.Message</p>

<p>Data: <input asp-for="Name"></p>

<button type="submit">Submit</button>
</form>

动作方法如下,

[HttpGet]
ViewResult Registration()
{
    ViewBag.Message=ModelState.IsValid;
    return View();
}

[HttpPost]
ViewResult Registration(Student s)
{
    if(!ModelState.IsValid){
       ViewBag.Message=false;
       return View();
    }
}
  • 当表单字段无效时,框架如何知道ModelState.IsValid 在 HTTPGET 中必须为真,而在 HTTPPOST 中必须为假?对我来说,传递给用户的空白视图表单(通过操作方法的 HttpGet 版本)应该使 ModelState.IsValid 为 false。

  • 额外问题:当返回无效表单并保留输入的数据字段时,为什么我们不需要return View(s); 而不是return View();?对我来说,return View(); 似乎返回了一个空白表格。

【问题讨论】:

  • 你的 GET 方法没有接收到模型(它没有任何参数)所以没有任何东西被添加到 ModelState 所以它总是 true (在 POST 方法中,你的方法有一个参数对于模型)
  • 额外问题解释:默认路由引擎配置为在返回空参数视图时遵循动作方法名称。因此,如果您将return View() 提交为ViewResult,默认情况下,路由模式会搜索与声明的操作名称具有相同名称的视图。
  • return View(); 确实返回一个“空白”(默认实例)模型。如果您在视图中包含&lt;div&gt;@Model.SomeProperty&lt;/div&gt;,它将引发异常。表单控件中的值首先从ModelState 填充(如果它们存在)(它们确实存在)
  • return View(); 或 return View(s); 在 ModelState.IsValid 为 false 的情况下工作相同。
  • 我将添加一个简短的答案来解释行为:)

标签: c# asp.net asp.net-mvc


【解决方案1】:

当您发出请求(GET 或 POST)时,DefaultModelBinder 从请求中读取值(查询字符串参数、路由值、表单值等),初始化您方法中的任何参数,并尝试设置它们的值.

对于您的 GET 方法,您没有模型作为参数,因此无需初始化,也无需设置任何内容,因此不会将任何内容添加到 ModelState 和 ModelState.IsValid 返回 true (仅当设置模型属性的值导致验证错误时才返回 false)。

对于 POST 方法,您有一个参数 Student s,因此会初始化模型的新实例。如果您的文本框为空,则会添加一个 ModelState 错误,因为 [Required] 属性(默认情况下,空字符串表示 null)并且 ModelState.IsValid 将返回 false。


使用return View(); 将返回当前视图而不将模型传递给视图。使用HtmlHelper 方法生成的任何表单控件都使用来自ModelState 的值(如果存在)(如果不存在,则从ViewDataDictionary 中读取该值,然后从实际模型中读取)因此,如果您最初发布"xyz",则Name: "xyz" 的 / 值对将添加到 ModelState。您的@Html.TextBoxFor(m =&gt; m.Name) 方法在ModelState 中找到匹配项,并且文本框的值设置为“xyz”。作为证明,如果在 POST 方法中,您将使用

s.Name = "Another Value";
return View(s);

您会看到文本框保留了您发布的原始值,而不是“另一个值”

如果您还包含&lt;div&gt;@Model.Name&lt;/div&gt;,则会抛出NullReferenceException(因为您无法访问null 的Name 属性),因此您应该始终将模型返回到视图。

【讨论】:

    猜你喜欢
    • 2020-06-13
    • 1970-01-01
    • 2019-05-15
    • 1970-01-01
    • 2010-10-14
    • 2011-07-03
    • 2018-07-03
    • 2020-08-23
    • 1970-01-01
    相关资源
    最近更新 更多