上一章提到可在 HttpModule 初始化前動態新增 Route 以自訂 HttpHandler 接管請求,MVC 是否採用相同機制?本章透過分析 MVC 3 原始碼驗證此問題。
建立 MVC 3 Web Application 專案(預設範本含 HomeController、AccountController)。MVC 必須先接管請求,才能透過 Controller/Action 處理。查看 Global.asax.cs 的 Application_Start:
RegisterRoutes(RouteTable.Routes);
RegisterRoutes 方法:
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
參數為全域靜態集合 RouteTable.Routes。MapRoute 並非 RouteCollection 內建方法,而是 MVC 提供的擴展方法(位於 RouteCollectionExtensions):
public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) {
if (routes == null) throw new ArgumentNullException("routes");
if (url == null) throw new ArgumentNullException("url");
Route route = new Route(url, new MvcRouteHandler()) {
Defaults = new RouteValueDictionary(defaults),
Constraints = new RouteValueDictionary(constraints),
DataTokens = new RouteValueDictionary()
};
if ((namespaces != null) && (namespaces.Length > 0)) {
route.DataTokens["Namespaces"] = namespaces;
}
routes.Add(name, route);
return route;
}
此方法建立 Route 並加入 RouteTable.Routes,符合先前分析的動態註冊機制。關鍵在於傳入 MvcRouteHandler 實例。
查看 MvcRouteHandler.GetHttpHandler:
public class MvcRouteHandler : IRouteHandler {
protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) {
requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));
return new MvcHandler(requestContext);
}
// ... 其他程式碼
}
它實作 IRouteHandler,回傳 MvcHandler 實例,而 MvcHandler 實作 IHttpHandler 與 IHttpAsyncHandler,即 MVC 專屬處理常式。之後呼叫 BeginProcessRequest 進入 MVC 管線處理。
至此,MVC 在 ASP.NET Runtime 中接管請求的完整路徑已釐清。後續章節將深入分析 MvcHandler 實作細節。此外,我們也可嘗試自行撰寫自訂 HttpHandler 透過 Route 動態註冊,實現自訂擴充功能。