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

ASP.NET MVC Filter 與 Action 執行管線深度解析:Authorize、Action、Result、Exception 四大 Filter 完整流程

     編輯:ASP.NET 基礎

從 Controller 執行到 ActionInvoker

Controller.ExecuteCore() → ActionInvoker.InvokeAction() 是核心入口。流程:

  1. 取得 ControllerDescriptor、ActionDescriptor (反射 MethodInfo)。
  2. GetFilters:彙總三類 Filter Provider:
  • GlobalFilters.Filters (Application_Start 註冊)
  • FilterAttributeFilterProvider (Attribute 標記)
  • ControllerInstanceFilterProvider (Controller 實作介面)
  1. 依序執行四類 Filter:
類型介面執行時機典型用途
AuthorizationIAuthorizationFilter最先,Action 前登入驗證、權限檢查
ActionIActionFilterAction 前/後日誌、效能計時、ModelState 驗證
ResultIResultFilterActionResult 執行前/後輸出快取、壓縮、修改 ViewData
ExceptionIExceptionFilter發生未處理例外時錯誤記錄、友善錯誤頁、例外轉換

Authorization Filter 執行細節

protected virtual AuthorizationContext InvokeAuthorizationFilters(...) {
    var context = new AuthorizationContext(controllerContext, actionDescriptor);
    foreach (var filter in filters) {
        filter.OnAuthorization(context);
        if (context.Result != null) break; // 短路:直接回傳結果 (如導向登入頁)
    }
    return context;
}

關鍵:context.Result 一旦被設定 (如 new HttpUnauthorizedResult()),後續 Filter 與 Action 皆**跳過**,直接進入 InvokeActionResult。

Action Filter:雙向鏈與異常處理

InvokeActionMethodWithFilters 使用 委托鏈 (Continuation) 實現「洋蔥模型」:

Func<ActionExecutedContext> continuation = () => 
    new ActionExecutedContext(...) { Result = InvokeActionMethod(...) };

// 反向疊加:f3 → f2 → f1 → Action → f1 → f2 → f3
Func<ActionExecutedContext> thunk = filters.Reverse().Aggregate(continuation,
    (next, filter) => () => InvokeActionMethodFilter(filter, preContext, next));

return thunk(); // 執行整條鏈

InvokeActionMethodFilter 核心邏輯

filter.OnActionExecuting(preContext); // 前置
if (preContext.Result != null) return 已取消的結果; // 短路

try {
    postContext = continuation(); // 執行下一層 (或 Action)
}
catch (ThreadAbortException) { // Response.Redirect 導致
    filter.OnActionExecuted(postContext); throw;
}
catch (Exception ex) {
    filter.OnActionExecuted(new ActionExecutedContext(..., ex));
    if (!postContext.ExceptionHandled) throw; // 未處理則向上拋
}
if (!wasError) filter.OnActionExecuted(postContext); // 正常後置
return postContext;

實際執行順序 (3 個 Action Filter)

f3.OnActionExecuting
  f2.OnActionExecuting
    f1.OnActionExecuting
      Action 執行
    f1.OnActionExecuted
  f2.OnActionExecuted
f3.OnActionExecuted

註解揭密:// need to reverse the filter list because the continuations are built up backward — 反向疊加才能產生正向執行順序。

Result Filter:類似 Action Filter

針對 ActionResult 執行前 (OnResultExecuting) 與後 (OnResultExecuted),同樣使用委托鏈。

Exception Filter:捕獲未處理例外


catch (Exception ex) {
    var exceptionContext = InvokeExceptionFilters(controllerContext, exceptionFilters, ex);
    if (!exceptionContext.ExceptionHandled) throw;
    InvokeActionResult(controllerContext, exceptionContext.Result);
}
  • 若 ExceptionHandled = true,吞掉例外並執行 Result (如錯誤視圖)。
  • 若 false,重新拋出 → ASP.NET 全域錯誤處理 (customErrors/yellow screen)。

Action 方法執行:ReflectedActionDescriptor

最終透過 ActionMethodDispatcher.Execute(controller, parameters) 呼叫。原始碼使用 Expression 動態編譯委托以提升效能 (避免每次反射),等價於:

// 原始碼複雜,本質等同於:
return methodInfo.Invoke(controller, parameters);

完整調用圖概覽

Controller.ExecuteCore
  → ActionInvoker.InvokeAction
      → GetFilters (3 Providers)
      → InvokeAuthorizationFilters (短路可跳過後續)
      → ValidateRequest / GetParameterValues (Model Binding)
      → InvokeActionMethodWithFilters (Action Filter 鏈 + Action)
      → InvokeActionResultWithFilters (Result Filter 鏈 + ActionResult)
      → catch → InvokeExceptionFilters

實務啟示

  1. Filter 順序:Global → Controller 層級 Attribute → Action 層級 Attribute → Controller 介面實作。
  2. 短路機制:任一階段設定 context.Result 即可攔截流程 (如 [Authorize] 失敗導向登入)。
  3. 異常處理層級:Action Filter 可處理 Action 例外;Exception Filter 可處理所有階段例外 (含 Filter 自身)。
  4. 非同步 Action:MVC 4+ 支援 async Task<ActionResult>,Filter 同步執行,Action 非同步,管線自動等待。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved