DataAnnotationsModelValidatorProvider 是 ASP.NET MVC 預設最重要的 ModelValidatorProvider,負責將 ValidationAttribute 轉換為對應的 ModelValidator。本文深入剖析其內部工廠機制與擴充介面。
類別內部維護四組靜態工廠委派與字典:
| 欄位 | 型別 | 用途 |
|---|---|---|
| AttributeFactories | Dictionary<Type, DataAnnotationsModelValidationFactory> | 特定 ValidationAttribute 型別對應的自訂 ModelValidator 工廠 |
| DefaultAttributeFactory | DataAnnotationsModelValidationFactory | 預設工廠,建立通用 DataAnnotationsModelValidator |
| ValidatableFactories | Dictionary<Type, DataAnnotationsValidatableObjectAdapterFactory> | 實作 IValidatableObject 的型別對應工廠 |
| DefaultValidatableFactory | DataAnnotationsValidatableObjectAdapterFactory | 預設 IValidatableObject 適配器工廠,建立 ValidatableObjectAdapter |
static DataAnnotationsModelValidatorProvider()
{
// 1. 預設 ValidationAttribute 工廠
DefaultAttributeFactory = (metadata, context, attribute) => new DataAnnotationsModelValidator(metadata, context, attribute);
// 2. 內建四大屬性專用適配器
var dict = new Dictionary<Type, DataAnnotationsModelValidationFactory>();
dict.Add(typeof(RangeAttribute), (m, c, a) => new RangeAttributeAdapter(m, c, (RangeAttribute)a));
dict.Add(typeof(RegularExpressionAttribute), (m, c, a) => new RegularExpressionAttributeAdapter(m, c, (RegularExpressionAttribute)a));
dict.Add(typeof(RequiredAttribute), (m, c, a) => new RequiredAttributeAdapter(m, c, (RequiredAttribute)a));
dict.Add(typeof(StringLengthAttribute), (m, c, a) => new StringLengthAttributeAdapter(m, c, (StringLengthAttribute)a));
AttributeFactories = dict;
// 3. IValidatableObject 預設工廠
DefaultValidatableFactory = (metadata, context) => new ValidatableObjectAdapter(metadata, context);
ValidatableFactories = new Dictionary<Type, DataAnnotationsValidatableObjectAdapterFactory>();
}
ModelMetadata 取得所有 Attribute。ValidationAttribute 的屬性。AttributeFactories 查找型別專用工廠。DefaultAttributeFactory。ModelValidator 加入結果集。IValidatableObject:
ValidatableFactories 查找型別專用工廠。DefaultValidatableFactory。雖然工廠字典為 internal,但提供公開靜態方法供開發者註冊自訂適配器:
// ValidationAttribute 適配器註冊
public static void RegisterAdapter(Type attributeType, Type adapterType);
public static void RegisterAdapterFactory(Type attributeType, DataAnnotationsModelValidationFactory factory);
public static void RegisterDefaultAdapter(Type adapterType);
public static void RegisterDefaultAdapterFactory(DataAnnotationsModelValidationFactory factory);
// IValidatableObject 適配器註冊
public static void RegisterValidatableObjectAdapter(Type modelType, Type adapterType);
public static void RegisterValidatableObjectAdapterFactory(Type modelType, DataAnnotationsValidatableObjectAdapterFactory factory);
public static void RegisterDefaultValidatableObjectAdapter(Type adapterType);
public static void RegisterDefaultValidatableObjectAdapterFactory(DataAnnotationsValidatableObjectAdapterFactory factory);
RegisterAdapter:指定 attributeType 對應的 adapterType,該型別需有 (ModelMetadata, ControllerContext, ValidationAttribute) 建構子。RegisterAdapterFactory:直接提供工廠委派,彈性最高。RegisterDefaultAdapter:設定預設適配器型別(用於無專用適配器的 Attribute)。RegisterValidatableObjectAdapter:針對特定 modelType 註冊 IValidatableObject 適配器,建構子為 (ModelMetadata, ControllerContext)。若自訂 AgeRangeAttribute : ValidationAttribute, IClientValidatable,需:
IsValid。GetClientValidationRules 產生 ModelClientValidationRule。
3. 註冊伺服器端適配器:DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(AgeRangeAttribute), typeof(AgeRangeAttributeAdapter));
4. AgeRangeAttributeAdapter 繼承 DataAnnotationsModelValidator<AgeRangeAttribute> 並覆寫 GetClientValidationRules 回傳前端規則。
DataAnnotationsModelValidatorProvider 採用工廠模式解耦屬性與 Validator 建立邏輯,靜態字典提供高效查找,公開註冊方法開放完整擴充點。掌握其機制可輕鬆整合自訂驗證屬性、客戶端規則或替換預設行為。