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

ASP.NET MVC 將 ValidationAttribute 直接套用至 Action 參數實現參數層級驗證

     編輯:關於ASP.NET

背景:為何需要參數層級驗證?

ASP.NET MVC 預設僅解析 Model 類別及其屬性上的 ValidationAttribute。若能直接標註於 Action 參數,將解決兩大痛點:

  1. 無法修改原生型別:如 int、string 等無法加上屬性。
  2. 同一 Model 不同情境需不同規則:參數層級屬性可覆蓋或補充 Model 定義的規則。

核心挑戰:框架不解析參數屬性

ModelValidator 建立時基於 ModelMetadata(描述型別/屬性),完全忽略 ParameterDescriptor 上的屬性。需擴充管線使參數屬性參與驗證。

解決方案:自訂 ActionInvoker 攔獲 ParameterDescriptor

1. 繼承 ControllerActionInvoker / AsyncControllerActionInvoker

覆寫 GetParameterValue,在繫結參數前將 ParameterDescriptor 暫存至 ControllerContext.RouteData.DataTokens,繫結後移除:

public class ParameterValidationActionInvoker : ControllerActionInvoker
{
    protected override object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
    {
        try
        {
            controllerContext.RouteData.DataTokens.Add("ParameterDescriptor", parameterDescriptor);
            return base.GetParameterValue(controllerContext, parameterDescriptor);
        }
        finally
        {
            controllerContext.RouteData.DataTokens.Remove("ParameterDescriptor");
        }
    }
}

public class ParameterValidationAsyncActionInvoker : AsyncControllerActionInvoker
{
    protected override object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
    {
        try
        {
            controllerContext.RouteData.DataTokens.Add("ParameterDescriptor", parameterDescriptor);
            return base.GetParameterValue(controllerContext, parameterDescriptor);
        }
        finally
        {
            controllerContext.RouteData.DataTokens.Remove("ParameterDescriptor");
        }
    }
}

2. 註冊自訂 ActionInvoker

在 Global.asax 或 Controller 工廠中替換預設 Invoker:

ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory());
// 或在 Controller 建構子指定
public HomeController() { this.ActionInvoker = new ParameterValidationActionInvoker(); }

3. 自訂 ModelValidatorProvider 讀取參數屬性

繼承 DataAnnotationsModelValidatorProvider,覆寫 GetValidators:

  • 從 ControllerContext.RouteData.DataTokens["ParameterDescriptor"] 取得 ParameterDescriptor。
  • 呼叫 parameterDescriptor.GetCustomAttributes(true) 獲取參數上的 ValidationAttribute。
  • 合併 Model 屬性屬性與參數屬性,建立對應 ModelValidator。

實際應用範例

public ActionResult Register(
    [Required(ErrorMessage = "請輸入帳號")]
    [StringLength(20, ErrorMessage = "帳號長度不可超過 20 字元")]
    string username,
    
    [Required(ErrorMessage = "請輸入密碼")]
    [DataType(DataType.Password)]
    string password)
{
    // 參數層級驗證自動生效
}

限制與注意

  • 參數屬性僅能驗證參數本身(型別層級),無法深入驗證複雜型別參數的內部屬性(需搭配 Model 層級屬性)。
  • 需同時處理同步/非同步 Controller,故需兩個 Invoker 實作。
  • 效能影響極小,僅在繫結階段額外讀取屬性。

總結

透過自訂 ActionInvoker 攔獲 ParameterDescriptor 並存入 RouteData.DataTokens,配合擴充 ModelValidatorProvider 讀取參數屬性,成功將 ValidationAttribute 擴展至 Action 參數層級,靈活解決原生型別驗證與多情境驗證需求。

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