旨在為目標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: }