【发布时间】:2013-12-16 15:21:46
【问题描述】:
我有一个模型(简化)如下:
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 也有客户端验证。这非常有效。
现在问题来了……
我发布以下值:
状态 = AL
StateString = null
国家 = 美国
这符合我的验证规则,应该是有效的。这是但是。 ModelState 告诉我它无效。显然 StateString 字段是必需的。那不是我指定的。为什么我的验证规则没有按预期应用?
(如果您知道此时出了什么问题,那么就不必阅读剩下的问题)
所以这就是正在发生的事情。 RequiredIfAttribute 被触发了 3 次。但是等等,我只用了两次。它正在像这样被触发:
- 在
StateString上触发(返回无效) - 在
State上触发(返回有效) - 在
StateString上触发(返回有效)
这很奇怪。它验证StateString 两次,第一次通过,第二次失败。剧情变厚了……
我对此进行了进一步调查,发现它第一次尝试验证StateString,Country 未设置。第二次尝试验证StateString,Country is 已设置。仔细观察,似乎第一次验证StateString 的尝试发生在我的模型完全绑定之前。 StateString(在代码中)下方的所有属性(未在示例模型中列出)均未绑定。第二次尝试验证StateString,绑定所有属性。
我已经解决了这个问题,但我对它没有信心,因为我根本不信任它。为了让我的验证按预期工作,我重新排列了模型(为简洁起见删除了属性):
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. 我怎样才能阻止这种行为?
【问题讨论】:
-
你是如何解决这个问题的?
标签: asp.net-mvc validation asp.net-mvc-4 model-binding model-validation