我有一个模型(简化),如下所示:
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/