Model验证系统运行机制是如何实现的?2012-09-24 cnblogs Artech在前面三篇文章(《ModelValidator》、《ModelValidatorProvider》和《ModelValidatorProviders》)中我们详细介绍了真正用于Model验证的ModelValidator以及相关的提供机制,接下来我们来讨论一下在这个以ModelValidator为核心的Model验证系统中,通过Model绑定得到的数据对象的验证是如何实现的。一、从ModelState谈起我们知道Controller对象的ViewData包含有个元素类型为ModelState的集合,用于表示Model的状态。除了在Model绑定过程通过ValueProvider体工的数据保存在该集合中之外,提供数据的验证结果也保存其中。
 1: [Serializable]
 2: public class ModelState
 3: {
 4: public ModelErrorCollection Errors { get; }
 5: public ValueProviderResult Value { get; set;}
 6: }
 7:
 8: [Serializable]
 9: public class ModelErrorCollection : Collection<ModelError>
10: {
11: public ModelErrorCollection();
12: public void Add(Exception exception);
13: public void Add(string errorMessage);
14: }
15:
16: [Serializable]
17: public class ModelError
18: {
19: public ModelError(Exception exception);
20: public ModelError(string errorMessage);
21: public ModelError(Exception exception, string errorMessage);
22:
23: public string ErrorMessage { get; }
24: public Exception Exception { get; }
25: }
通过上面的代码片断所示,ModelState具有Value和Errors两个核心属性,前者表示ValueProvider提供的ValueProviderResult对象,后者表示针对该数据对象的错误集合,其类型为ModelErrorCollection。ModelErrorCollection是一个元素类型为ModelError的集合,而一个ModelError对象通过错误消息和异常来描述错误。二、实例演示:验证Model绑定过程中对ModelError的设置Model验证可以看成是Model绑定过程的一部分,它在生成目标Action方法参数值的过程中会对提供的数据实施验证,而在验证失败的情况下验证结果会以ModelError的形式写入当前Controller的ViewData的ModelState中,现在我们通过一个简单的实例来证实这一点。我们还是将多次使用的Contact作为Model类型,如下面的代码片断所示,类型Contact和Address以及它们的所有属性应用了上面定义的验证特性AlwaysFailsAttribute(《ASP.NET MVC以ModelValidator为核心的Model验证体系: ModelValidatorProviders》),并设置了相应的错误信息。
 1: [AlwaysFails(ErrorMessage = "Contact")]
 2: public class Contact
 3: {
 4: [AlwaysFails(ErrorMessage = "Contact.Name")]
 5: public string Name { get; set; }
 6:
 7: [AlwaysFails(ErrorMessage = "Contact.PhoneNo")]
 8: public string PhoneNo { get; set; }
 9:
10: [AlwaysFails(ErrorMessage = "Contact.EmailAddress")]
11: public string EmailAddress { get; set; }
12:
13: [AlwaysFails(ErrorMessage = "Contact.Address")]
14: public Address Address { get; set; }
15: }
16:
17: [AlwaysFails(ErrorMessage = "Address")]
18: public class Address
19: {
20: [AlwaysFails(ErrorMessage = "Address.Province")]
21: public string Province { get; set; }
22:
23: [AlwaysFails(ErrorMessage = "Address.City")]
24: public string City { get; set; }
25:
26: [AlwaysFails(ErrorMessage = "Address.District")]
27: public string District { get; set; }
28:
29: [AlwaysFails(ErrorMessage = "Address.Street")]
30: public string Street { get; set; }
31: }