Controller.ExecuteCore() → ActionInvoker.InvokeAction() 是核心入口。流程:
ControllerDescriptor、ActionDescriptor (反射 MethodInfo)。GlobalFilters.Filters (Application_Start 註冊)FilterAttributeFilterProvider (Attribute 標記)ControllerInstanceFilterProvider (Controller 實作介面)| 類型 | 介面 | 執行時機 | 典型用途 |
|---|---|---|---|
| Authorization | IAuthorizationFilter | 最先,Action 前 | 登入驗證、權限檢查 |
| Action | IActionFilter | Action 前/後 | 日誌、效能計時、ModelState 驗證 |
| Result | IResultFilter | ActionResult 執行前/後 | 輸出快取、壓縮、修改 ViewData |
| Exception | IExceptionFilter | 發生未處理例外時 | 錯誤記錄、友善錯誤頁、例外轉換 |
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。
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(); // 執行整條鏈
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;
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 — 反向疊加才能產生正向執行順序。
針對 ActionResult 執行前 (OnResultExecuting) 與後 (OnResultExecuted),同樣使用委托鏈。
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)。最終透過 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
context.Result 即可攔截流程 (如 [Authorize] 失敗導向登入)。async Task<ActionResult>,Filter 同步執行,Action 非同步,管線自動等待。