背景 : 對HttpModule 、HttpHandler和HttpApplication管線有一定的了解
ASP.NET MVC 應用程式的啟動流程 :
1、Application啟動時先通過RouteTable把URL映射到Handler
2、UrlRoutingModule(HttpModule)在PostResolveRequestCache事件中攔截用戶請求(在Init中註冊要攔截的事件),解析 request 並選取路由。
ASP.NET MVC 應用程式的啟動流程 :
1、Application啟動時先通過RouteTable把URL映射到Handler
2、UrlRoutingModule(HttpModule)在PostResolveRequestCache事件中攔截用戶請求(在Init中註冊要攔截的事件),解析 request 並選取路由。
HttpModule 是註冊在 Web.config 中的,例如:
<configuration>
<system.web>
<httpModules>
<!-- <add name="HelloWorldModule"
type="HelloWorldModule, HelloWorldModule" /> -->
</httpModules>
</system.web>
</configuration>
可是當打開Asp.net MVc 應用程式的 Web .Config 時卻沒有發現UrlRoutingModule的配置節,原因是:"它已經默認的寫在全局的中"。應此可以在“$\Windows\Microsoft.NET\Framework\版本號\Config\Web.config“ 中找到" <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" /> ”
開始自定MVC流程
using System; using System.Web; using System.Web.Routing; namespace Practice_MvcModule { /// <summary> /// 實作 IHttpHandler 介面來自定 HttpHandler(類似 MvcHander) /// </summary> public class MyTestingMvcHandler : IHttpHandler { public MyTestingMvcHandler(RequestContext requestContext) { this.RequestContext = requestContext; } #region IHttpHandler 的成員 public bool IsReusable { get { return true; } } // 啟用 HTTP Web 要求的處理 (Override the ProcessRequest method. ) public void ProcessRequest(HttpContext context) { // 簡單地把路由訊息用文字輸出到頁面上 (應該需要對 Controller 加載, 激活並執行) context.Response.Write(String.Format("<h1>This is an HttpHandler Test.</h1><br/>{0} Controller and {1} action " , this.RequestContext.RouteData.Values["Controller"] , this.RequestContext.RouteData.Values["Action"])); context.Response.End(); } #endregion public RequestContext RequestContext { get; private set; } } /// <summary> /// 自定的處理比對路徑(類似 MvcRouteHandler) /// </summary> public class MyTestingRouteHandler : IRouteHandler { // 當路由被捕獲時, 返回一個 MyTestingMvcHandler public IHttpHandler GetHttpHandler(RequestContext requestContext) { return new MyTestingMvcHandler(requestContext); } IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext) { return this.GetHttpHandler(requestContext); } } /// <summary> /// 擴展 RouteCollection, 新增自訂方法 /// 說明 : /// 在Global.asax.cs 或 Route.Config.cs 的 RegisterRoutes 方法裡, RouteCollection 類使用的是 MapRoute 方法添加的路由, /// 該方法是一個擴展方法, 它位於System.Web.Mvc 的 RouteCollectionExtensions 類中 /// </summary> public static class MyTestingRouteCollectionExtensions { /// <summary> /// 對應指定的 URL 路由並設定預設路由值、條件約束和命名空間 /// </summary> /// <param name="routes">應用程式的路由集合</param> /// <param name="name">要對應之路由的名稱</param> /// <param name="url">路徑的 URL 模式</param> /// <param name="defaults">包含預設路由值的物件</param> /// <returns></returns> public static Route MyTestingMapRoute(this RouteCollection routes, string name, string url, object defaults) { return MyTestingMapRoute(routes, name, url, defaults, null, null); } /// <param name="constraints">為 url 參數指定值的一組運算式</param> /// <param name="namespaces">應用程式的命名空間集合</param> public static Route MyTestingMapRoute(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 和 MyTestingRouteHandler 的映射關係 Route route = new Route(url, new MyTestingRouteHandler()) { 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; } } /// <summary> /// 自訂的 HttpModule(類似 UrlRoutingModule) /// </summary> public class MyTestingHttpModule : IHttpModule { public void Init(HttpApplication context) { // 在 HttpApplication 管線抵達 PostMapRequestHandler 之前要先找到處理常式 context.PostResolveRequestCache += new EventHandler(context_PostResolveRequestCache); } void context_PostResolveRequestCache(object sender, EventArgs e) { // 包裝目前的 HttpContext 物件 HttpContextBase context = new HttpContextWrapper(((HttpApplication)sender).Context); // 將包裝後的 HttpContext 物件傳給 RouteTable, 透過要求參數在路由表中比對路由物件, 然後回傳第一個符合的 RouteData 路由物件 (獲取路由訊息) RouteData routeData = RouteTable.Routes.GetRouteData(context); if (routeData == null) { return; } // 獲取 IRouteHandler 的實例 (例如 MvcRouteHandler, 或是自定的 MyTestingRouteHandler) IRouteHandler routeHandler = routeData.RouteHandler; if (routeHandler == null) { throw new InvalidOperationException(); } // 成功取得 RouteData 路由物件後, 建立表示目前 HttpContext 和 RouteData 的 RequestContext 物件 (建構請求上下文) RequestContext requestContext = new RequestContext(context, routeData); // 把 RequestContext 物件傳給 Handler 的建構式, 取得一個基於 RouteTable 的新 HttpHandler IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext); if (httpHandler == null) { throw new InvalidOperationException("無法建立對應的 HttpHandler 物件"); } // 將 HttpHandler 實例映射到 HttpApplication 管線中 context.RemapHandler(httpHandler); } public void Dispose() { throw new NotImplementedException(); } } }
新增路由規則
using System.Web.Mvc; using System.Web.Routing; namespace Practice_MvcModule { public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MyTestingMapRoute( // MyTestingMapRoute 為自行擴展 RouteCollection 的方法 name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } } }
配置自定的 HttpModule
<configuration>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="MyTestingHttpModule" type="Practice_MvcModule.MyTestingHttpModule"/>
<!--
<add name="MyTestingHttpModule" type="命名空間.類別名稱[,程式集名稱(因為直接在目錄中所以此範例可以不用指定)]"/>
-->
</modules>
</system.webServer>
</configuration>
asp.net mvc 簡易流程說明:
UrlHttpModule的Init註冊了要攔截 PostResolveRequestCache 事件,在該事件中處理解析 request 並獲取 IRouteHandler 的實例 MvcRouteHandler (路由處理常式),根據 MvcRouteHandler 的 GetHttpHandler 方法獲取 IHttpHandler 的實例 MvcHandler,透過 MvcHandler 的 ProcessRequest 方法對 Controller 加載, 激活並執行。
UrlHttpModule的Init註冊了要攔截 PostResolveRequestCache 事件,在該事件中處理解析 request 並獲取 IRouteHandler 的實例 MvcRouteHandler (路由處理常式),根據 MvcRouteHandler 的 GetHttpHandler 方法獲取 IHttpHandler 的實例 MvcHandler,透過 MvcHandler 的 ProcessRequest 方法對 Controller 加載, 激活並執行。
沒有留言:
張貼留言