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

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

我需要的验证规则是:
  • 如果Country是USA,则需要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也具有客户端验证。这完美地工作。

    现在到问题了...

    我要发布以下值:



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

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

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

  • 这很奇怪。两次验证StateString,第一次通过,第二次失败。情节变浓了...

    我对此进行了进一步调查,发现它第一次尝试验证StateString时,未将Country 设置为。第二次尝试验证StateString时,已将Country 设置为。仔细观察,似乎第一次验证StateString的尝试是在我的模型完全绑定(bind)之前发生的。没有绑定(bind)StateString(在代码中)下面的所有属性(在示例模型中未列出)。第二次尝试验证StateString,绑定(bind)了所有属性。

    我已经解决了这个问题,但是我对此并不自信,因为我根本不信任它。为了使我的验证按预期工作,我对模型进行了重新排列(为简洁起见,删除了属性):
    public UserModel {
        ...
        public Country Country {get; set; }
        public USState State {get; set; }
        public string StateString {get; set; }
        ...
    }
    
    RequiredIfAttribute仍然如上所述触发三遍,但是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/

    10-17 00:54