【问题标题】:ASP.NET MVC 5 model validation for non-nullable types (Int32)非空类型 (Int32) 的 ASP.NET MVC 5 模型验证
【发布时间】:2016-06-28 08:57:48
【问题描述】:

我正在开发一个 ASP.NET MVC 5 应用程序,项目所有者担心由于验证不可为空的类型(如 http://bradwilson.typepad.com/blog/2010/01/input-validation-vs-model-validation-in-aspnet-mvc.htmlhttp://www.asp.net/web-api/overview/formats-and-model-binding/model-validation-in-aspnet-web-api 中所述)导致的“发布不足”问题。

我创建了一个测试用例来在 ASP.NET MVC 5 中复制这个问题,但没有运气。

型号:

public class ContactModel
{
    [Required]
    public Int32 data1 { get; set; }

    public Int32 data2 { get; set; }
}

查看:

<div class="form-group">
    @Html.LabelFor(model => model.data1)
    <div>
        @Html.EditorFor(model => model.data1)
    </div>
</div>  
<div>
    @Html.LabelFor(model => model.data2)
    <div>
        @Html.EditorFor(model => model.data2)
    </div>
</div>

控制器:

public ActionResult Index(Models.ContactModel contact)
{
    if (ModelState.IsValid)
    {
        Response.Write("modelstate is valid<br>");

        return View();
    }
    else
    {
        Response.Write("modelstate is invalid<br>");

        return View();
    }
}

似乎data1data2在post中为null时,它们在模型(contact)中的值将为0。但是,ModelState.IsValid也会为false (而不是两篇文章中显示的true)。

我有什么:

第二篇文章展示的内容:

我找不到任何有关 ASP.NET MVC 中模型验证工作方式更改的信息,所以我猜我的测试用例做错了。任何想法和建议都表示赞赏。

【问题讨论】:

  • 您不需要 [Required] 属性上的 int 属性(除非您想要自定义错误消息) - int 永远不能是 nullDefaultModelBinder 添加了一个错误,因为您不能将 null 分配给 int 并设置 ModelState.IsValid = false。但是值是0,因为这是int的默认值
  • @StephenMuecke 这就是我最初的想法。但根据 Brad Wilson 的帖子(我的问题中的第一个链接):其分支是不可为空值类型上的 [Required] 不能作为表单包含值的保证。如果不包含值,则跳过模型绑定,即不会发生模型绑定失败。此外,当 [Required] 验证器运行时,它会从模型中查询值——其中将包含值类型的默认值,通常为 0——并说“这不是 null,这里一切都很好!”。
  • 这是错误的,模型绑定永远不会被跳过。如果为具有[Required] 属性的值类型或引用类型的属性发送值,ModelState.IsValid 将始终为 false
  • 如果你想对整数类型进行验证,[Required] 属性在这种特定场景下是无用的。正如文章中所说:这是否是一个问题取决于您的方案。因此,如果您想对整数类型进行验证,我建议使用 [Range] 验证属性,因为它在这种情况下更有意义。

标签: asp.net-mvc asp.net-mvc-5 model-validation


【解决方案1】:

您的 ModelState 为 false 的原因是该帖子提供了模型中每个属性的表单值。本质上,模型绑定系统正在检查 data1 和 data2 字段的有效性,因为您在视图中为这两个属性显式编写了 @Html.EditorFor 帮助器(因此实际上没有进行过低发布)。

我确实成功地复制了文章中发布不足的问题。只需在您的视图中删除一个 EditorFor 助手,这样您实际上就没有发布。有两个助手都在场,就不会出现低调的情况。所以视图现在看起来像这样(注意,我为这两个属性添加了验证帮助程序,以便在视图中获得关于正在发生的事情的反馈):

查看:

<div class="form-group">
    @Html.LabelFor(model => model.data1)
    <div>
        @Html.EditorFor(model => model.data1)
        @Html.ValidationMessageFor(model => model.data1)
        @Html.ValidationMessageFor(model => model.data2)
    </div>
</div>

确保为 data2 属性完全关闭 @Html.EditorFor 助手。现在在表单域中填写零(当然现在您只会在视图中显示一个表单域),然后发布到您的操作中。

在这种情况下,ModelState 将返回为 true,即使只发布了一个表单字段。如果有人不张贴,这不是一个好结果!因此,这是(稍作修改的)原始模型类,如果表单字段未从表单中删除,则会出现过帐问题(请注意,必需属性在这种情况下没有任何区别,因为两个属性都是值类型):

//You could add the Required attribute or not, doesn't matter at this point.
//The concern here is that the Modelstate will still come back as Valid
//in the case of a form field being left off of your form (or someone underposts).
//So to replicate underposting issues, make sure to comment or delete
//at least one Html.EditorFor helper in the view.

//[Required] Underposting will occur regardless if this is marked required or not,
//so be careful if someone does underpost your form.
public Int32 data1 { get; set; }

//[Required]
public Int32 data2 { get; set; }

如果您想解决发布不足的问题,现在的解决方案是: 只需根据需要标记这两个属性,并按照您提供的文章中所述将它们设为可空,如下所示:

[Required]
public Int32? data1 { get; set; }

[Required]
public Int32? data2 { get; set; }

现在,当发布视图时缺少 @H​​tml.EditorFor 帮助程序或缺少表单字段,ModelState 验证将返回为 false,并且您可以避免发布不足的问题。

【讨论】:

  • 谢谢!这听起来确实很有希望。我将在今天晚些时候尝试复制它,如果可行,请标记答案。
  • 真棒吉姆。我通过调试器运行它并验证了行为,所以一切都应该工作。如果您对此有任何疑问,请告诉我。顺便说一句,我很高兴我遇到了你的问题。该Required 属性可能会产生误导,如果您不小心,您可能会突然将属性设置为其默认值。谢谢,蒂姆
猜你喜欢
  • 2015-02-26
  • 1970-01-01
  • 1970-01-01
  • 2010-11-18
  • 2011-12-24
  • 1970-01-01
  • 2014-06-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多