根據 Http Runtime 與 Pipeline 分析,ASP.NET 應用程式可擁有多個 HttpModule,但僅有一個 HttpHandler,透過其 BeginProcessRequest 處理回應。MapHttpHandler 階段會依 URL 查找對應的 HttpHandler。MVC 透過註冊路由(Route)對應 Controller/Action,但首先必須有 MVC 專屬的 MvcHandler 被 MapRequestHandler 找到並套用。由於 URL 無副檔名,無法直接進入 ASP.NET Runtime;MVC 2 需註冊通配符映射,配合自訂 UrlRoutingModule 匹配路由;MVC 3 則將路由匹配機制整合至 ASP.NET 4.0 核心,即本文主角 UrlRoutingModule。
UrlRoutingModule 繼承 IHttpModule,其 Init 方法:
protected virtual void Init(HttpApplication application) {
if (application.Context.Items[_contextKey] != null) return;
application.Context.Items[_contextKey] = _contextKey;
application.PostResolveRequestCache += OnApplicationPostResolveRequestCache;
}
掛載事件於 PostResolveRequestCache(而非 MapRequestHandler),因 IIS 6 不支援後者,為相容性採用前一階段事件。
OnApplicationPostResolveRequestCache 核心邏輯:
public virtual void PostResolveRequestCache(HttpContextBase context) {
RouteData routeData = RouteCollection.GetRouteData(context);
if (routeData == null) return;
IRouteHandler routeHandler = routeData.RouteHandler;
if (routeHandler == null) throw new InvalidOperationException(...);
if (routeHandler is StopRoutingHandler) return;
RequestContext requestContext = new RequestContext(context, routeData);
context.Request.RequestContext = requestContext;
IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
if (httpHandler == null) throw new InvalidOperationException(...);
if (httpHandler is UrlAuthFailureHandler) { ... }
context.RemapHandler(httpHandler);
}
流程:依 URL 從路由表取得 RouteData → 取得 IRouteHandler → 建立 RequestContext → 呼叫 GetHttpHandler 取得 IHttpHandler → 透過 context.RemapHandler 將請求轉交給該處理常式(即 MvcHandler)。此機制完美整合於 ASP.NET 管線,無需通配符映射即可支援無副檔名 URL。