asp.net-mvc - ASP.NET MVC 模型绑定(bind)和验证顺序

标签 asp.net-mvc validation asp.net-mvc-4 model-binding model-validation

我有一个模型(简化)如下:

public UserModel {
    ...
    public USState State {get; set; }
    public string StateString {get; set; }
    public Country Country {get; set; }
    ...
}

我需要的验证规则是:
  • 如果 Country是美国然后State是必须的。
  • 如果 Country那时不是美国StateString是必须的。

  • 我创建了一个自定义验证属性 RequiredIfAttribute .这很好用,所以我不会用它的实现来回答这个问题。它具有三个必需的成员:
  • CompareField - 这是用于检查是否需要验证的字段。
  • CompareValue - 这是它将比较以确定是否需要验证的值。
  • CompareType - 这是它将如何比较值来决定是否需要验证。

  • 所以有了这个,我更新我的模型:
    public UserModel {
        ...
        [RequiredIf("Country", Country.USA, EqualityType.Equals)]    
        public USState State {get; set; }
        [RequiredIf("Country", Country.USA, EqualityType.NotEquals)] 
        public string StateString {get; set; }
        [Required]                                                   
        public Country Country {get; set; }
        ...
    }
    

    我应该在这里注意到我的RequiredIfAttribute也有客户端验证。这完美地工作。

    现在说问题...

    我发布以下值:

    State = AL
    StateString = null
    Country = USA



    这符合我的验证规则,应该是有效的。这是但是。 ModelState告诉我这是无效的。显然 StateString 字段是必需的。那不是我指定的。为什么我的验证规则没有按预期应用?

    (如果您知道此时出了什么问题,那么不必阅读问题的其余部分)

    这就是正在发生的事情。 RequiredIfAttribute被触发了 3 次。但是等等,我只用了两次。它正在像这样被触发:
  • 触发 StateString (返回 无效 )
  • 触发 State (返回 有效 )
  • 触发 StateString (返回 有效 )

  • 这很奇怪。它正在验证 StateString两次,第一次通过,第二次失败。剧情变厚了……

    我对此进行了进一步调查,发现它第一次尝试验证 StateString , Country 不是 放。第二次尝试验证 StateString , Country 放。仔细观察,似乎第一次尝试验证 StateString在我的模型完全绑定(bind)之前发生。 StateString 以下的所有属性(示例模型中未列出) (在代码中)不受约束。第二次尝试验证StateString ,所有属性都是绑定(bind)的。

    我已经解决了这个问题,但我对它没有信心,因为我根本不相信它。为了让我的验证按预期工作,我重新排列了模型(为简洁起见,删除了属性):
    public UserModel {
        ...
        public Country Country {get; set; }
        public USState State {get; set; }
        public string StateString {get; set; }
        ...
    }
    
    RequiredIfAttribute仍然像上面一样触发 3 次,但是 ModelState告诉我发布的数据(如上)现在是有效的,就像魔术一样!

    我看到的是这个(我的假设):
    1. Start binding (property by property, top to bottom in code (risky))
    2. Arrive at `StateString` and decide to try and validate
    3. Finish binding
    4. Validate all properties
    

    我真的有两个问题:
    1. 为什么会出现这种行为?
    2. 我怎样才能阻止这种行为?

    最佳答案

    模型绑定(bind)过程中存在大量错综复杂的情况。复杂模型将被完全重新验证。

    我建议为了更好地理解该过程,您可以深入研究源代码以了解实际发生的情况。

    http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Http/ModelBinding/Binders/MutableObjectModelBinder.cs

    有一个后处理阶段:

    // post-processing, e.g. property setters and hooking up validation
    ProcessDto(actionContext, bindingContext, dto);
    bindingContext.ValidationNode.ValidateAllProperties = true; // complex models require full validation
    

    有一个预处理阶段:
    // 'Required' validators need to run first so that we can provide useful error messages if
    // the property setters throw, e.g. if we're setting entity keys to null. See comments in
    // DefaultModelBinder.SetProperty() for more information.
    

    除了实现自己的模型绑定(bind)器之外,似乎没有很多方法可以影响这一点。

    关于asp.net-mvc - ASP.NET MVC 模型绑定(bind)和验证顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20302529/

    相关文章:

    c# - 在 C# 中针对嵌入式 XSD 验证 XML

    jquery - 如何在 ASP.NET MVC 中为有效字段添加绿色边框

    javascript - 当 jquery.validate 验证表单时启用提交按钮

    javascript - 在mvc View 中反序列化Json

    asp.net-mvc-4 - NopCommerce : Display best seller products on category home page

    c# - 如何获得相同时间的日期时间?

    .net - 重定向时将数组或字符串列表从一个操作传递到另一个操作

    c# - VS 2017 : Property value is not valid. - 启用 SSL

    c# - MVC 列表 ViewModel 在表单提交时未绑定(bind)

    asp.net-mvc - asp.net mvc app_data 文件夹