在前面三篇文章(《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: }