首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> 關於ASP.NET

ASP.NET MVC ValidationAttribute 核心機制:錯誤訊息、驗證執行與死循環避免

     編輯:關於ASP.NET

ValidationAttribute 基礎結構

所有驗證屬性繼承自 System.ComponentModel.DataAnnotations.ValidationAttribute,核心成員:

public abstract class ValidationAttribute : Attribute
{
    public string ErrorMessage { get; set; }
    public string ErrorMessageResourceName { get; set; }
    public Type ErrorMessageResourceType { get; set; }
    protected string ErrorMessageString { get; } // 最終錯誤訊息文字
    
    public virtual string FormatErrorMessage(string name); // 格式化訊息,name 為顯示名稱
    
    public virtual bool IsValid(object value); // 簡單驗證入口
    protected virtual ValidationResult IsValid(object value, ValidationContext validationContext); // 完整驗證入口
    
    public void Validate(object value, string name); // 拋出驗證例外
    public ValidationResult GetValidationResult(object value, ValidationContext validationContext); // 統一入口
}

錯誤訊息定義優先順序與格式化

  1. 資源檔優先:若設定 ErrorMessageResourceName + ErrorMessageResourceType,忽略 ErrorMessage。
  2. 訊息模板:支援預留位置,如 "{0}必須在{1}和{2}之間"。
  3. FormatErrorMessage:預設實作 string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name),name 為 DisplayName。預設僅支援 {0},需覆寫以支援多參數或具名預留位置。

驗證執行雙入口與死循環機制

兩個 IsValid 互相呼叫:

// 簡單版呼叫完整版
public virtual bool IsValid(object value) 
    => IsValid(value, null) == ValidationResult.Success;

// 完整版呼叫簡單版(預設)
protected virtual ValidationResult IsValid(object value, ValidationContext context)
    => IsValid(value) ? ValidationResult.Success : new ValidationResult(FormatErrorMessage(context?.DisplayName));

結果:若衍生類別兩者皆未覆寫,將陷入無限遞迴。框架內部偵測此情況並拋出 NotImplementedException:「此類尚未實現 IsValid(object value)。首選入口點是 GetValidationResult(),並且類應重寫 IsValid(object value, ValidationContext context)。」

正確實作模式

  • 僅覆寫簡單版:適用無需 ValidationContext 的單值驗證。
  • 僅覆寫完整版:需存取 ValidationContext(如跨屬性比較、資料庫查詢)。
  • 兩者皆覆寫:需自行避免互呼叫,通常完整版呼叫簡單版或反之,但不可形成循環。

GetValidationResult 統一入口流程

    1. 建立 ValidationContext(若未提供)。 2. 呼叫 IsValid(value, context)。 3. 若回傳 ValidationResult.Success 直接回傳;否則以 ErrorMessage 或格式化訊息建立新 ValidationResult 回傳。

Validate 方法:拋出例外的驗證方式

public void Validate(object value, string name)
{
    var result = GetValidationResult(value, new ValidationContext(value) { DisplayName = name });
    if (result != ValidationResult.Success)
        throw new ValidationException(result.ErrorMessage);
}

適用於需立即中斷流程的場合(如手動驗證)。

實作範例:自訂 AgeRangeAttribute

public class AgeRangeAttribute : ValidationAttribute
{
    public int MinAge { get; }
    public int MaxAge { get; }
    
    public AgeRangeAttribute(int min, int max) { MinAge = min; MaxAge = max; }
    
    // 覆寫完整版,需計算年齡
    protected override ValidationResult IsValid(object value, ValidationContext context)
    {
        if (value is DateTime birthDate)
        {
            int age = DateTime.Today.Year - birthDate.Year;
            if (birthDate > DateTime.Today.AddYears(-age)) age--;
            if (age >= MinAge && age <= MaxAge) return ValidationResult.Success;
        }
        return new ValidationResult(FormatErrorMessage(context.DisplayName));
    }
    
    // 覆寫格式化支援多參數
    public override string FormatErrorMessage(string name)
        => string.Format(ErrorMessageString, name, MinAge, MaxAge);
}

總結

ValidationAttribute 以雙 IsValid 入口提供彈性,框架透過 NotImplementedException 強制開發者實作至少一個。錯誤訊息支援資源檔與格式化模板,FormatErrorMessage 為客製化關鍵。掌握此機制可建構強健、可維護的自訂驗證屬性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved