DataAnnotationsModelValidator最終是通過它對應的ModelValidatorProvider,即DataAnnotationsModelValidatorProvider創建的。通過前面的介紹我們知道它是AssociatedValidatorProvider的子類,後者在用於獲取ModelValidator的GetValidators方法中已經根據指定的Model元數據所有特性創建出來,DataAnnotationsModelValidator只需要從中篩選出繼承自ValiationAttribute的驗證特性並創建對象的DataAnnotationsModelValidator就可以了。
DataAnnotationsModelValidator
我們現在結合DataAnnotationsModelValidator的相關定義來討論一下具體的ModelValidator提供機制。如下面的代碼片斷所示,DataAnnotationsModelValidatorProvider具有兩個靜態的字段AttributeFactories和DefaultAttributeFactory,後者是一個DataAnnotationsModelValidationFactory委托,前者是以此委托為Value以Type對象為Key的字典。
1: public class DataAnnotationsModelValidatorProvider : AssociatedValidatorProvider
2: {
3: //其他成員
4: internal static readonly Dictionary<Type, DataAnnotationsModelValidationFactory> AttributeFactories;
5: internal static DataAnnotationsModelValidationFactory DefaultAttributeFactory;
6:
7: internal static DataAnnotationsValidatableObjectAdapterFactory DefaultValidatableFactory;
8: internal static readonly Dictionary<Type, DataAnnotationsValidatableObjectAdapterFactory> ValidatableFactories;
9:
10: protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, HttpActionContext actionContext, IEnumerable<Attribute> attributes);
11: }
12:
13: public delegate ModelValidator DataAnnotationsModelValidationFactory(ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute);
14:
15: public delegate ModelValidator DataAnnotationsValidatableObjectAdapterFactory(ModelMetadata metadata, ControllerContext context);
基於ValidationAttribute的ModelValidator的創建
委托DataAnnotationsModelValidationFactory根據ModelMetadata、ControllerContext和ValidationAttribute返回一個ModelValidator對象,而字段AttributeFactories表示的字典對象的Key是具體的驗證特性的類型,也就是說它維護一個ValidationAttribute特性類型和對應ModelValidator工廠的匹配關系。在重寫的GetValidators方法中,針對指定的每一個ValidationAttribute,它先根據其類型從AttributeFactories中獲取一個對應的DataAnnotationsModelValidationFactory委托,如果該委托存在,則用它來創建相應的ModelValidator對象;否則就采用字段DefaultAttributeFactory表示的DataAnnotationsModelValidationFactory委托來進行ModelValidator的創建。
基於IValidatableObject的ModelValidator的創建
除了AttributeFactories和DefaultAttributeFactory,DataAnnotationsModelValidatorProvider還具有DefaultValidatableFactory和ValidatableFactories這兩個靜態屬性,它們用於針對可驗證對象(實現了IValidatableObject接口)的ModelValidator的創建。DataAnnotationsModelValidator的類型是另外一個類型為DataAnnotationsValidatableObjectAdapterFactory的委托,該委托根據ModelMetadata和ControllerContext創建相應的ModelValidator。ValidatableFactories是一個以此委托為Value,以Type對象為Key的字典。
當DataAnnotationsModelValidatorProvider完成了針對基於驗證特性的ModelValidator的創建之後,如果根據Model元數據解析出來的Model類型實現了IValidatableObject接口,那麼先從字典ValidatableFactories中根據此類型獲取一個對應的DataAnnotationsValidatableObjectAdapterFactory委托,如果匹配的委托對象存在,則用其進行ModelValidator的創建;否則采用通過字段DefaultValidatableFactory表示的默認工廠來創建相應的ModelValidator對象。
默認的ModelValidator創建機制
在DataAnnotationsModelValidatorProvider類型被加載的時候,上述的四個字段會在靜態構造函數調用時被初始化。從如下的代碼片斷可看出,對於一般的ValidationAttribute,對應的ModelValidator是一個DataAnnotationsModelValidator對象(DefaultAttributeFactory字段);針對RangeAttribute、RegularExpressionAttribute 、RequiredAttribute和StringLengthAttribute這四種驗證特性,它們對應的適配ModelValidator會被創建出來。而對於可驗證對象來說,默認情況下提供的ModelValidator列表中還包含一個ValidatableObjectAdapter對象。
1: public class DataAnnotationsModelValidatorProvider : AssociatedValidatorProvider
2: {
3: //其他成員
4: static DataAnnotationsModelValidatorProvider()
5: {
6: //1、DefaultAttributeFactory
7: DefaultAttributeFactory = (metadata, context, attribute) => new DataAnnotationsModelValidator(metadata, context, attribute);
8:
9: //2、AttributeFactories
10: Dictionary<Type, DataAnnotationsModelValidationFactory> dictionary = new Dictionary<Type, DataAnnotationsModelValidationFactory>();
11: dictionary.Add(typeof(RangeAttribute), (metadata, context, attribute) => new RangeAttributeAdapter(metadata, context, (RangeAttribute)attribute));
12: dictionary.Add(typeof(RegularExpressionAttribute), (metadata, context, attribute) => new RegularExpressionAttributeAdapter(metadata, context, (RegularExpressionAttribute)attribute));
13: dictionary.Add(typeof(RequiredAttribute), (metadata, context, attribute) => new RequiredAttributeAdapter(metadata, context, (RequiredAttribute)attribute));
14: dictionary.Add(typeof(StringLengthAttribute), (metadata, context, attribute) => new StringLengthAttributeAdapter(metadata, context,(StringLengthAttribute)attribute));
15: AttributeFactories = dictionary;
16:
17: //3、DefaultValidatableFactory
18: DefaultValidatableFactory = (metadata, context) => new ValidatableObjectAdapter(metadata, context);
19:
20: //4、ValidatableFactories
21: ValidatableFactories = new Dictionary<Type, DataAnnotationsValidatableObjectAdapterFactory>();
22: }
23: }
對ModelValidator創建方式的定制
DataAnnotationsModelValidatorProvider四個基於委托的靜態字段體現了其采用的ModelValidator提供機制。由於它們都是內部字段,我們不能直接對其進行操作,但是如下所示的一系列靜態方法在DataAnnotationsModelValidatorProvider中定義出來,使我們可以按照具體的需要對默認的ModelValidator進行定義。
1: public class DataAnnotationsModelValidatorProvider : AssociatedValidatorProvider
2: {
3: //其他成員
4: public static void RegisterAdapter(Type attributeType, Type adapterType);
5: public static void RegisterAdapterFactory(Type attributeType, DataAnnotationsModelValidationFactory factory);
6: public static void RegisterDefaultAdapter(Type adapterType);
7: public static void RegisterDefaultAdapterFactory(DataAnnotationsModelValidationFactory factory);
8:
9: public static void RegisterDefaultValidatableObjectAdapter(Type adapterType);
10: public static void RegisterDefaultValidatableObjectAdapterFactory(DataAnnotationsValidatableObjectAdapterFactory factory);
11: public static void RegisterValidatableObjectAdapter(Type modelType, Type adapterType);
12: public static void RegisterValidatableObjectAdapterFactory(Type modelType, DataAnnotationsValidatableObjectAdapterFactory factory);
13: }
對於上面的8個靜態方法,除了RegisterDefaultAdapter和RegisterValidatableObjectAdapter之外,其余的都很好理解。RegisterDefaultAdapter用於注冊一個默認的針對驗證特性的ModelValidator類型,該類型必須具有一個參數類型列表為ModelMetadata、ControllerContext和Attribute的構造函數。如果根據 驗證特性的類型找到了匹配的DataAnnotationsModelValidationFactory委托對象,相應的參數會被傳入該構造函數並最終創建一個我們注冊的ModelValidator對象。
RegisterValidatableObjectAdapter和RegisterDefaultAdapter比較類似,用於注冊一個默認的針對可驗證對象類型的ModelValidator,有該類型必須具有一個參數類型列表為ModelMetadata和ControllerContex的構造函數。如果根據 驗證特性的類型找到了匹配的DataAnnotationsValidatableObjectAdapterFactory委托對象,相應的參數會被傳入該構造函數並最終創建一個我們注冊的ModelValidator對象。