旨在為目標Action方法的執行綁定輸入參數的Model綁定過程伴隨著對Model的驗證。借助相應的驗證特性,我們可以直接以聲明的方式在Model類型上定義驗證規則,這些規則將會作為Model元數據的一部分。具體在Model綁定過程中,ModelBinder通過ValueProvider為Model對象的某個屬性提供相應屬性值之後,會根據定義在基於該屬性的Model元數據的驗證規則實施驗證。ASP.NET MVC的整個Model驗證系統以組件ModelValidator為核心,或者說Model對象的驗證最終通過某個ModelValidator對象來完成,所以我們有必要先來認識一下ModelValidator以及背後的提供機制。
一、ModelValidator
在ASP.NET MVC應用編程接口中,所有的ModelValidator都直接或者間接地繼承自抽象類型ModelValidator。如下面的代碼片斷所示,ModelValidator具有一個布爾類型的只讀屬性IsRequired,表示該ModelValidator是否是對目標數據進行必要性的驗證,默認返回False。GetClientValidationRules返回一個元素類型為ModelClientValidationRule的集合。ModelClientValidationRule是對客戶端驗證規則的封裝,我們會在進行客戶端驗證時對其進行詳細介紹。
1: public abstract class ModelValidator
2: {
3: //其他成員
4: public virtual IEnumerable<ModelClientValidationRule> GetClientValidationRules();
5: public abstract IEnumerable<ModelValidationResult> Validate(object container);
6:
7: public virtual bool IsRequired { get; }
8: }
真正對目標數據實施驗證是通過調用Validate方法來完成的,而該方法的輸入參數container表示的正式被驗證的對象。該Validate返回一個表示驗證結果的元素類型為ModelValidationResult的集合,該類型的定義如下所示。
1: public class ModelValidationResult
2: {
3: public ModelValidationResult();
4:
5: public string MemberName { get; set; }
6: public string Message { get; set; }
7: }
ModelValidationResult具有兩個字符串類型的屬性MemberName和Message,前者代表被驗證數據成員的名稱,後者表示錯誤消息。一般來說,當它們用於驗證某個復雜類型對象的時候,針對於類型本身驗證返回的ModelValidationResult對象的MemberName屬性為空字符串;而對於針對屬性驗證來說,屬性名稱直接作為MemberName屬性值。
ModelClientValidationRule集合只有在驗證失敗的情況下才會返回。如果目標數據符合所有的驗證規則,Validate方法會直接返回Null或者一個空ModelValidationResult集合。值得一提的是,我們在調用ModelValidator的Validate方法確定目標數據是否通過驗證時,有時候會將方法返回值和定義在類型ValidationResult中具有如下定義的靜態只讀字段Success進行比較。實際上,表示驗證成功的Success字段值就是Null。
1: public class ValidationResult
2: {
3: //其他成員
4: public static readonly ValidationResult Success;
5: }
二、DataAnnotationsModelValidator
稍微了解ASP.NET MVC的讀者應該知道,我們可以通過數據類型的某個屬性上應用相應的驗證標注特性(比如RequiredAttribute、RangeAttribute和RegularExpressionAttribute等)的方式來定義相應的驗證規則,這是ASP.NET MVC 提供的默認Model驗證方式。這種基於數據標注(Data Annotation)特性的驗證對應的ModelValidator類型為DataAnnotationsModelValidator,我們會在後續的文章中對其進行單獨介紹。
三、ClientModelValidator
ClientModelValidator是定義在程序集System.Web.Mvc.dll中的內部類型,在客戶端用於數據類型的驗證。如下面的代碼片斷所示,在構造函數中除了指定Model元數據和Controller上下文之外,還需要以字符串的形式指定驗證類型(數據類型)和錯誤消息。
1: internal class ClientModelValidator : ModelValidator
2: {
3: public ClientModelValidator(ModelMetadata metadata, ControllerContext controllerContext, string validationType,string errorMessage);
4: public sealed override IEnumerable<ModelClientValidationRule> GetClientValidationRules();
5: public sealed override IEnumerable<ModelValidationResult> Validate(object container);
6: }
由於ClientModelValidator僅限於客戶端驗證,其Validate方法(服務端驗證)總是返回一個空的ModelValidationResult集合,而GetClientValidationRules方法會根據指定的驗證類型和錯誤消息生成相應的客戶端驗證規則。
ClientModelValidator具有兩個繼承者,分別是數值類型和日期類型進行客戶端驗證的NumericModelValidator和DateModelValidator。如下面的代碼片斷所示,這兩個ClientModelValidator用於表示驗證數據類型的字符串分別是“number”和“date”。而表示錯誤消息的字符串是從內部維護的資源文件中獲取的。這實際上帶來了一個問題,我們無法對錯誤消息進行定制。
1: internal sealed class NumericModelValidator :ClientModelValidator
2: {
3: public NumericModelValidator(ModelMetadata metadata, ControllerContext controllerContext)
4: : base(metadata, controllerContext, "number", ClientDataTypeModelValidatorProvider.GetFieldMustBeNumericResource(controllerContext))
5: {
6: }
7: }
8:
9: internal sealed class DateModelValidator :ClientModelValidator
10: {
11: public DateModelValidator(ModelMetadata metadata, ControllerContext controllerContext)
12: : base(metadata, controllerContext, "date", ClientDataTypeModelValidatorProvider.GetFieldMustBeDateResource(controllerContext))
13: {
14: }
15: }