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

ASP.NET MVC 13 大擴展點深度解析:從路由到視圖渲染的完整管線可替換性

     編輯:關於ASP.NET

ASP.NET MVC 核心設計原則是 **「慣例優於配置」** 與 **「全管線可替換」**。Simone Chiaretta 整理的 13 大擴展點涵蓋從請求進入到視圖輸出的完整管線,掌握這些點即掌握 MVC 框架的靈魂。以下逐一深度解析並附實務應用場景。

1. RouteConstraint (路由約束)

介面:`IRouteConstraint` (`bool Match(HttpContext, Route, string, RouteValueDictionary, RouteDirection)`)

應用:複雜參數驗證 (如日期有效性、跨參數關聯驗證)。


public class ValidDateConstraint : IRouteConstraint
{
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, 
                      RouteValueDictionary values, RouteDirection routeDirection)
    {
        if (values.TryGetValue("year", out var y) && 
            values.TryGetValue("month", out var m) && 
            values.TryGetValue("day", out var d))
        {
            return DateTime.TryParse($"{y}-{m}-{d}", out _);
        }
        return false;
    }
}

// 路由註冊
routes.MapRoute("Archive", "archive/{year}/{month}/{day}", 
    new { controller = "Blog", action = "Archive" },
    new { year = @"\d{4}", month = @"\d{2}", day = @"\d{2}" }, // 正則
    new[] { "MyApp.Controllers" });
// 或使用約束物件
routes.MapRoute("Archive", "archive/{year}/{month}/{day}", 
    new { controller = "Blog", action = "Archive" },
    new { year = new ValidDateConstraint() });

2. RouteHandler (路由處理器)

介面:`IRouteHandler` (`IHttpHandler GetHttpHandler(RequestContext)`)

應用:將特定路由導向非 MVC 處理器 (Web Forms、靜態檔案、SignalR、自訂 HttpHandler)。


public class LegacyAspxRouteHandler : IRouteHandler
{
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        string virtualPath = "~/Legacy/Pages/" + requestContext.RouteData.Values["page"] + ".aspx";
        return BuildManager.CreateInstanceFromVirtualPath(virtualPath, typeof(Page)) as IHttpHandler;
    }
}

// 註冊
routes.Add(new Route("legacy/{page}", new LegacyAspxRouteHandler()));

3. ControllerFactory (控制器工廠)

抽象類:`DefaultControllerFactory` / 介面 `IControllerFactory`

應用:依賴注入 (IoC) 整合、多租戶控制器解析、動態載入外掛控制器。


// 整合 Autofac / Unity / Ninject / 建構子注入
public class IoCControllerFactory : DefaultControllerFactory
{
    private readonly IContainer _container;
    public IoCControllerFactory(IContainer container) => _container = container;

    protected override IController GetControllerInstance(RequestContext context, Type controllerType)
    {
        if (controllerType == null) return null;
        return (IController)_container.Resolve(controllerType); // IoC 容器建構並注入依賴
    }
}

// Application_Start
ControllerBuilder.Current.SetControllerFactory(new IoCControllerFactory(container));

4. ActionInvoker (動作執行器)

類別:`ControllerActionInvoker`

應用:自訂動作選擇邏輯、參數繫結規則、Filter 執行順序、非同步動作包裝。


public class CustomActionInvoker : ControllerActionInvoker
{
    protected override ActionDescriptor FindAction(ControllerContext context, ControllerDescriptor controller, string actionName)
    {
        // 例:支援動作名稱別名、大小寫不敏感
        return base.FindAction(context, controller, actionName.ToLowerInvariant());
    }

    protected override IDictionary GetParameterValues(ControllerContext context, ActionDescriptor action)
    {
        // 例:從 Header、Claim、Session 自動繫結參數
        return base.GetParameterValues(context, action);
    }
}

// 控制器掛載
public class BaseController : Controller
{
    protected override IActionInvoker CreateActionInvoker() => new CustomActionInvoker();
}

5. ActionMethodSelectorAttribute (動作方法選擇器)

抽象類:`ActionMethodSelectorAttribute` (`bool IsValidForRequest(ControllerContext, MethodInfo)`)

應用:依據 Accept-Language、User-Agent、自訂 Header 選擇不同動作。


public class BrowserSpecificAttribute : ActionMethodSelectorAttribute
{
    public string BrowserType { get; set; } // "Mobile", "Desktop", "Bot"
    
    public override bool IsValidForRequest(ControllerContext context, MethodInfo methodInfo)
    {
        string ua = context.HttpContext.Request.UserAgent?.ToLower() ?? "";
        return BrowserType switch
        {
            "Mobile" => ua.Contains("mobile") || ua.Contains("android") || ua.Contains("iphone"),
            "Desktop" => !ua.Contains("mobile"),
            "Bot" => ua.Contains("bot") || ua.Contains("crawler"),
            _ => true
        };
    }
}

// 使用
public class HomeController : Controller
{
    [BrowserSpecific(BrowserType = "Mobile")]
    public ActionResult Index() => View("Index.Mobile");

    [BrowserSpecific(BrowserType = "Desktop")]
    public ActionResult Index() => View("Index.Desktop");
}

6. AuthorizationFilter (授權過濾器)

介面:`IAuthorizationFilter` (`void OnAuthorization(AuthorizationContext)`)

應用:自訂權限檢查、多因子驗證、IP 白名單、API Key 驗證。


public class ApiKeyAuthorizationFilter : IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationContext filterContext)
    {
        string apiKey = filterContext.HttpContext.Request.Headers["X-Api-Key"];
        if (!ApiKeyStore.IsValid(apiKey))
        {
            filterContext.Result = new HttpUnauthorizedResult("Invalid API Key");
        }
    }
}

// 全域註冊 (GlobalFilters)
GlobalFilters.Filters.Add(new ApiKeyAuthorizationFilter());
// 或控制器/動作層級
[ApiKeyAuthorizationFilter]
public ActionResult SecureData() { ... }

7. ActionFilter (動作過濾器)

抽象類:`ActionFilterAttribute` (OnActionExecuting, OnActionExecuted, OnResultExecuting, OnResultExecuted)

應用:記錄、快取、ViewData 填充、模型狀態處理、單位工作提交。


public class ViewDataPopulateAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        // 所有 View 共用的資料集中注入
        filterContext.Controller.ViewBag.CurrentUser = GetCurrentUser();
        filterContext.Controller.ViewBag.SiteSettings = GetSiteSettings();
        filterContext.Controller.ViewBag.MenuItems = GetMenuItems();
    }
}

[ViewDataPopulate]
public class BaseController : Controller { }

8. ResultFilter (結果過濾器)

介面:`IResultFilter` (OnResultExecuting, OnResultExecuted)

應用:修改回應 Header、壓縮、加入通用 Footer、PDF/Excel 匯出包裝。

9. ExceptionFilter (例外過濾器)

介面:`IExceptionFilter` (`void OnException(ExceptionContext)`)

應用:全域例外處理、記錄、友善錯誤頁面、API 錯誤格式統一。


public class GlobalExceptionFilter : IExceptionFilter
{
    private readonly ILogger _logger;
    public GlobalExceptionFilter(ILogger logger) => _logger = logger;

    public void OnException(ExceptionContext filterContext)
    {
        if (filterContext.ExceptionHandled) return;
        
        _logger.Error(filterContext.Exception, "Unhandled exception");
        
        if (filterContext.HttpContext.Request.IsAjaxRequest())
        {
            filterContext.Result = new JsonResult 
            { 
                Data = new { error = "Server error", detail = filterContext.Exception.Message },
                JsonRequestBehavior = JsonRequestBehavior.AllowGet
            };
        }
        else
        {
            filterContext.Result = new ViewResult { ViewName = "Error" };
        }
        filterContext.ExceptionHandled = true;
    }
}

10. ModelBinder / ModelBinderProvider (模型繫結器)

介面:`IModelBinder` (`object BindModel(ControllerContext, ModelBindingContext)`)

應用:複雜型別繫結 (JSON Body、多部分表單、自訂格式)、加密 ID 解密、實體自動載入。


public class EntityModelBinder : IModelBinder where T : class, IEntity
{
    private readonly IRepository _repo;
    public EntityModelBinder(IRepository repo) => _repo = repo;

    public object BindModel(ControllerContext cc, ModelBindingContext bc)
    {
        var value = bc.ValueProvider.GetValue(bc.ModelName);
        if (value == null) return null;
        if (Guid.TryParse(value.AttemptedValue, out var id))
            return _repo.GetById(id);
        return null;
    }
}

// 註冊
ModelBinders.Binders.Add(typeof(Product), new EntityModelBinder(container.Resolve>()));

11. ModelValidatorProvider / ModelValidator (模型驗證提供者)

應用:自訂驗證規則 (跨欄位、資料庫唯一性、條件驗證)、移除預設 DataAnnotations 驗證。

12. ValueProviderFactory (值提供者工廠)

應用:支援新請求格式 (JSON、XML、Protobuf、QueryString 陣列格式)。


// ASP.NET MVC 3+ 內建 JsonValueProviderFactory
// 自訂範例:支援 application/x-msgpack
public class MsgPackValueProviderFactory : ValueProviderFactory
{
    public override IValueProvider GetValueProvider(ControllerContext cc)
    {
        if (cc.HttpContext.Request.ContentType?.StartsWith("application/x-msgpack") == true)
        {
            var dict = MsgPackSerializer.Deserialize>(cc.HttpContext.Request.InputStream);
            return new DictionaryValueProvider(dict, CultureInfo.CurrentCulture);
        }
        return null;
    }
}

// 註冊
ValueProviderFactories.Factories.Add(new MsgPackValueProviderFactory());

13. ViewEngine / View (視圖引擎)

介面:`IViewEngine` (FindView, FindPartialView, ReleaseView)

應用:多主題/皮膚、多租戶視圖解析、Razor 以外模板引擎 (Spark、NVelocity、Handlebars.NET)。


public class ThemedRazorViewEngine : RazorViewEngine
{
    private readonly string _theme;
    public ThemedRazorViewEngine(string theme) => _theme = theme;

    protected override IView CreateView(ControllerContext cc, string viewPath, string masterPath)
    {
        // 先找 Themes/{Theme}/Views/... 再找預設 Views/...
        return base.CreateView(cc, viewPath.Replace("~/Views/", $"~/Themes/{_theme}/Views/"), masterPath);
    }
}

// 註冊 (依租戶/主題動態決定)
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new ThemedRazorViewEngine(currentTenant.Theme));

管線流向總覽

Request 
  → RouteCollection (RouteConstraint) 
  → RouteHandler (IRouteHandler) 
  → MvcHandler 
    → ControllerFactory (IControllerFactory) 
    → Controller 
      → ActionInvoker (ControllerActionInvoker) 
        → ActionMethodSelectorAttribute 
        → AuthorizationFilter (IAuthorizationFilter) 
        → ActionFilter (OnActionExecuting) 
        → ModelBinder (IModelBinder) + ModelValidator 
        → Action 執行 
        → ActionFilter (OnActionExecuted) 
        → ResultFilter (OnResultExecuting) 
        → ActionResult 執行 (ViewResult → ViewEngine → View) 
        → ResultFilter (OnResultExecuted) 
        → ExceptionFilter (發生例外時)
Response

實務建議

  • **優先使用 Filter (Authorization/Action/Result/Exception)** 解決橫切關注點,保持 Controller 乾淨。
  • **IoC 整合透過 ControllerFactory**,動作層級依賴透過 ActionInvoker 或 Filter 屬性注入。
  • **路由約束處理參數格式,業務規則放 Authorization/ActionFilter**。
  • **視圖引擎替換極少見**,多主題改用 ViewEngine 繼承或 ViewLocationExpander (Core)。
  • **ASP.NET Core 中介軟體 取代 HttpModule/Handler,Filter 概念保留但介面調整**。

熟悉這 13 個擴展點,即能在不修改框架原始碼前提下,將 MVC 彎曲為任何業務形狀。

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