ASP.NET MVC模型绑定和验证顺序

时间:2013-11-30 16:17:53

标签: 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; }
    ...
}

我需要的验证规则是:

  1. 如果Country USA ,则需要State
  2. 如果Country不是美国,则需要StateString
  3. 我已经创建了自定义验证属性RequiredIfAttribute。这工作正常,所以我不打算用它的实现来填补这个问题。它有三个必需成员:

    1. CompareField - 这是用于检查是否需要验证的字段。
    2. CompareValue - 这是决定是否需要验证的价值。
    3. CompareType - 这是比较价值以决定是否需要验证的方式。
    4. 因此,我更新我的模型:

      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也有客户端验证。这非常有效。

      现在问题......

      我发布了以下值:

        

      州= AL
        StateString = null
        国家= 美国

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

      (如果您知道此时出现了什么问题,那么请不要感到有必要阅读其余问题)

      所以这就是发生的事情。 RequiredIfAttribute被触发三次。但是等等,我只使用它两次。正如这样被触发:

      1. 触发StateString(返回无效
      2. 触发State(返回有效
      3. 触发StateString(返回有效
      4. 这很奇怪。它正在验证StateString两次,第一次通过,第二次失败。情节变浓......

        我进一步调查了这一点,发现第一次尝试验证StateString时,Country 未设置。第二次尝试验证StateString时,Country 设置为。仔细观察,似乎第一次验证StateString的尝试是在我的模型完全绑定之前发生的。低于StateString(代码中)的所有属性(未在示例模型中列出)都不受约束。第二次尝试验证StateString,所有属性都被绑定。

        我已经解决了这个问题,但我对此并不自信,因为我根本不相信它。为了使我的验证按预期工作,我重新安排了模型(为了简洁而删除了属性):

        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.我该如何阻止这种行为?

1 个答案:

答案 0 :(得分:1)

模型绑定过程中存在大量复杂性。复杂模型将完全重新验证。

我建议为了更好地理解这个过程,您需要深入了解源代码,以了解真正发生的事情。

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.

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