封裝 ValidationAttribute,實作 ModelValidator 介面,提供伺服器端驗證邏輯與客戶端規則產生。
public class DataAnnotationsModelValidator : ModelValidator
{
public DataAnnotationsModelValidator(ModelMetadata metadata, ControllerContext context, ValidationAttribute attribute);
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules();
public override IEnumerable<ModelValidationResult> Validate(object container)
{
var validationContext = new ValidationContext(container ?? this.Metadata.Model, null, null)
{
DisplayName = this.Metadata.GetDisplayName()
};
var validationResult = this.Attribute.GetValidationResult(this.Metadata.Model, validationContext);
if (validationResult != ValidationResult.Success)
{
yield return new ModelValidationResult { Message = validationResult.ErrorMessage };
}
}
protected ValidationAttribute Attribute { get; }
protected string ErrorMessage { get; } // 來源於 Attribute.FormatErrorMessage(Metadata.DisplayName)
public override bool IsRequired { get; } // 僅 RequiredAttribute 回傳 true
}
ValidationContext,被驗證物件為 container 或 Metadata.Model,顯示名稱取自 Metadata.DisplayName。GetValidationResult(model, context)。ValidationResult.Success),包裝成 ModelValidationResult 回傳;成功則回傳空列舉。ErrorMessage:呼叫 Attribute.FormatErrorMessage(Metadata.DisplayName) 格式化錯誤訊息。IsRequired:僅當封裝屬性為 RequiredAttribute 時回傳 true,供前端 required 規則判斷。public class DataAnnotationsModelValidator<TAttribute> : DataAnnotationsModelValidator where TAttribute : ValidationAttribute
{
public DataAnnotationsModelValidator(ModelMetadata metadata, ModelBindingExecutionContext context, TAttribute attribute);
protected TAttribute Attribute { get; } // 強型別屬性存取
}
針對常用屬性提供強型別適配器,主要差異在覆寫 GetClientValidationRules 產生對應前端規則:
| 適配器 | 對應屬性 | 前端規則類型 | 關鍵參數 |
|---|---|---|---|
| RequiredAttributeAdapter | RequiredAttribute | required | 無 |
| RangeAttributeAdapter | RangeAttribute | range | min, max |
| RegularExpressionAttributeAdapter | RegularExpressionAttribute | regex | pattern |
| StringLengthAttributeAdapter | StringLengthAttribute | length | max |
public class AgeRangeAttribute : RangeAttribute, IClientValidatable
{
public AgeRangeAttribute(int min, int max) : base(min, max) { }
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
yield return new ModelClientValidationRule
{
ValidationType = "agerange",
ErrorMessage = FormatErrorMessage(metadata.DisplayName)
};
}
}
public class AgeRangeAttributeAdapter : DataAnnotationsModelValidator<AgeRangeAttribute>
{
public AgeRangeAttributeAdapter(ModelMetadata metadata, ControllerContext context, AgeRangeAttribute attribute)
: base(metadata, context, attribute) { }
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
yield return new ModelClientValidationRule
{
ValidationType = "agerange",
ErrorMessage = Attribute.FormatErrorMessage(Metadata.DisplayName)
};
}
}
// 註冊
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(AgeRangeAttribute), typeof(AgeRangeAttributeAdapter));
DataAnnotationsModelValidator 為驗證屬性與 MVC 驗證管線的橋樑,基類處理伺服器端驗證共通邏輯,泛型子類與四大專用適配器提供強型別存取與客戶端規則產生。自訂屬性只需實作 IClientValidatable 並註冊對應適配器即可無縫整合。