进入MVC处理通道
首先來看一下經(jīng)典的Asp.net處理管道的生命周期。
?
我們知道一個ASP.NET應(yīng)用程序可以有多個HttpModule,但是只能有一個HttpHandler,并且通過這個HttpHandler的BeginProcessRequest(或ProcessRequest)來處理并返回請求,查看聲明處理管道周期可知在MapHttpHandler這個周期將會根據(jù)請求的URL來查詢對應(yīng)的HttpHandler,那么它是如何查找的呢。
查找系統(tǒng)web.config中的httpModules配置節(jié),在倒數(shù)第二行發(fā)現(xiàn)一個name為UrlRoutingModule-4.0的IHttpModule配置,這是查找HttpHandler的關(guān)鍵之處。下面分析一下UrlRoutingModule的代碼:
????protected?virtual?void?Init(HttpApplication?application)?{????????if?(application.Context.Items[_contextKey]?!=?null)?{????????????return;}application.Context.Items[_contextKey]?=?_contextKey;application.PostResolveRequestCache?+=?OnApplicationPostResolveRequestCache;}????private?void?OnApplicationPostResolveRequestCache(object?sender,?EventArgs?e)?{HttpApplication?app?=?(HttpApplication)sender;HttpContextBase?context?=?new?HttpContextWrapper(app.Context);PostResolveRequestCache(context);}????public?virtual?void?PostResolveRequestCache(HttpContextBase?context)?{RouteData?routeData?=?RouteCollection.GetRouteData(context);……IRouteHandler?routeHandler?=?routeData.RouteHandler;……RequestContext?requestContext?=?new?RequestContext(context,?routeData);context.Request.RequestContext?=?requestContext;IHttpHandler?httpHandler?=?routeHandler.GetHttpHandler(requestContext);……context.RemapHandler(httpHandler);}可以看到UrlRoutingModule設(shè)置了一個PostResolveRequestCache事件處理方法,該方法從RouteCollection通過匹配找到請求對應(yīng)的路由數(shù)據(jù)RouteData(包含如Mvc中的Controller名、Action名等),然后從RouteData的屬性RouteHandler獲取一個IRouteHandler的實例,再從IRouteHandler實例里獲取對應(yīng)的IHttpHandler實例,最后調(diào)用HttpContext的RemapHandler方法重新為HttpContext設(shè)置RemapHandlerInstance。
根據(jù)前面asp.net初始化流程分析2我們知道在獲取Httphandler時經(jīng)典模式和集成模式使用了不同的IExecutionStep,經(jīng)典模式用的是MapHandlerExecutionStep集成模式用的是MaterializeHandlerExecutionStep,查看二者的執(zhí)行方法Execute。
先看MaterializeHandlerExecutionStep。
????void?IExecutionStep.Execute()?{HttpContext?context?=?_application.Context;HttpRequest?request?=?context.Request;IHttpHandler?handler?=?null;????????string?configType?=?null;……????????if?(context.RemapHandlerInstance?!=?null){wr.SetScriptMapForRemapHandler();context.Handler?=?context.RemapHandlerInstance;}……}可以看到MaterializeHandlerExecutionStep中如果UrlRoutingModule模塊中在HttpContext設(shè)置了RemapHandlerInstance,則直接用RemapHandlerInstance設(shè)置HttpContext的Handler。
再看MapHandlerExecutionStep。
????void?IExecutionStep.Execute()?{HttpContext?context?=?_application.Context;HttpRequest?request?=?context.Request;……context.Handler?=?_application.MapHttpHandler(context,?request.RequestType,?request.FilePathObject,?request.PhysicalPathInternal,?false?/*useAppConfig*/);……}在MapHandlerExecutionStep中會調(diào)用HttpApplication的MapHttpHandler方法來設(shè)置HttpContext的Handler。下面查看MapHttpHandler代碼:
????internal?IHttpHandler?MapHttpHandler(HttpContext?context,?String?requestType,?VirtualPath?path,?String?pathTranslated,?bool?useAppConfig)?{IHttpHandler?handler?=?(context.ServerExecuteDepth?==?0)???context.RemapHandlerInstance?:?null;????????using?(new?ApplicationImpersonationContext())?{????????????if?(handler?!=?null){????????????????return?handler;}……}從第一行代碼就可以看到如果HttpContext的RemapHandlerInstance不為空則直接返回HttpContext的RemapHandlerInstance(context.ServerExecuteDepth是指頁面是否使用了HttpServerUtility.Execute進行頁面內(nèi)跳轉(zhuǎn))。這樣也就同樣使用了UrlRoutingModule模塊中在HttpContext設(shè)置的RemapHandlerInstance,至于HttpContext沒有設(shè)置的RemapHandlerInstance的情況下如何根據(jù)默認的擴展名匹配查找HttpHandler就不在此討論了。
通過上面的分析我們可以設(shè)想通過在UrlRoutingModule中的靜態(tài)RouteCollection屬性中注冊RouteData而且設(shè)置該RouteData的IRouteHandler(一個接口,只有一個方法GetHttpHandler用來獲取HttpHandler)來實現(xiàn)路由與HttpHandler的對應(yīng)。下面來分析一下MvcHandler是如何通過路由注冊的,首先來看RouteCollection的實現(xiàn)
????public?RouteCollection?RouteCollection?{????????get?{????????????if?(_routeCollection?==?null)?{_routeCollection?=?RouteTable.Routes;}????????????return?_routeCollection;}????????set?{routeCollection?=?value;}}可以看到RouteCollection其實是包裝了RouteTable中的靜態(tài)Routes,如果有Mvc項目經(jīng)驗的話應(yīng)該很眼熟了,一般的Mvc程序在Global.asax中一般都有這么一段用來注冊路由:
????protected?void?Application_Start(){……RouteConfig.RegisterRoutes(RouteTable.Routes);……}????public?class?RouteConfig{????????public?static?void?RegisterRoutes(RouteCollection?routes){routes.IgnoreRoute("{resource}.axd/{*pathInfo}");routes.MapRoute(name:?"Default",url:?"{controller}/{action}/{id}",defaults:?new?{?controller?=?"Home",?action?=?"Index",?id?=?UrlParameter.Optional?});}}而我們定義的路由設(shè)置MvcHandler的奧妙正在MapRoute方法里,這是一個擴展方法,定義在System.Web.Mvc.RouteCollectionExtensions里:
public?static?Route?MapRoute(this?RouteCollection?routes,?string?name,?string?url,?object?defaults,?object?constraints,?string[]?namespaces){……Route?route?=?new?Route(url,?new?MvcRouteHandler()){Defaults?=?CreateRouteValueDictionaryUncached(defaults),Constraints?=?CreateRouteValueDictionaryUncached(constraints),DataTokens?=?new?RouteValueDictionary()};……routes.Add(name,?route);????????return?route;}可以看到MapRoute注冊路由是綁定了一個MvcRouteHandler作為IRouteHandler,下面看MvcRouteHandler是如何實現(xiàn)的:
????protected?virtual?IHttpHandler?GetHttpHandler(RequestContext?requestContext){requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));????????return?new?MvcHandler(requestContext);}在這里終于看到了創(chuàng)建MvcHandler的代碼。
至此,我們應(yīng)該有一個清晰的認識了,我們通過全局靜態(tài)屬性集合(RouteTable.Routes)去添加各種各樣的Route(但應(yīng)該在HttpModule初始化周期之前,一般是利用HttpApplication創(chuàng)建的周期在Application_Start方法中添加了我們所需要的Route規(guī)則),當(dāng)然在添加路由的時候帶上了MvcHandler這個重要的HttpHandler。然后通過UrlRoutingModule在PostResolveRequestCache周期通過查找注冊的Route獲取請求的RouteData以及其屬性IRouteHandler實例(至于路由是如何匹配的還要等后續(xù)的篇章繼續(xù)講),然后通過IRouteHandler實例可以通過GetHttpHandler獲取IHttpHandler并將其設(shè)置到HttpContext的RemapHandlerInstance屬性。最終在MapHttpHandler周期通過獲取HttpContext的RemapHandlerInstance實現(xiàn)了不同的HttpHandler來接管匹配不同路由的URL。
本文轉(zhuǎn)自xmgdc51CTO博客,原文鏈接:http://blog.51cto.com/12953214/1942930 ,如需轉(zhuǎn)載請自行聯(lián)系原作者
總結(jié)
- 上一篇: Java新手入门的30个基本概念
- 下一篇: s3c2440移植MQTT