上一節描述了API的整個運行框架,即分為三層hosting、message handler pipeline 和 controller handling。此節講其中一個宿主,WebHost 寄宿在asp.net 傳統管道上。
在asp.net平臺,路由是一般由RouteTables.Routes靜態屬性添加的,類型是RouteCollection,例如下面的MVC模板自帶的添加路由的代碼。
PRotected void application_Start(){ RegisterRoutes(RouteTable.Routes);} public static void RegisterRoutes(RouteCollection routes){ routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = UrlParameter.Optional } );}
大部分路由邏輯都是在UrlRoutingModule里,屬于PostResolveRequestCache asp.net管道事件。每一次請求,這個module都是重新匹配一次這個路由集合,并獲取一個RouteData實例,如果匹配,則:
1、實例化RouteData同時獲取一個route handler(HttpControllerRouteHandler)。
2、從routehandler獲取一個http handle 繼承自IHttphandler接口。IRouteHandler接口方法:IHttpHandler GetHttpHandler(RequestContext requestContext)
3、最后,當前的請求上下文(RequestContext)被映射到上面的這個httphandler。
因此,最后結果是asp.net管道請求被此handler處理。
當寄宿在asp.net上,Web API特定的配置被定義在一個單例模式的HttpConfiguration對象里,通過靜態屬性GlobalCnfiguration.Configuration訪問。
Web API 也定義了一對新的RouteCollection擴展方法MapHttpRoute,來注冊Web API特殊的路由,下面是配置的例子代碼:
HttpConfiguration config = GlobalConfiguration.Configuration;config.Routes.MapHttpRoute("default", "{controller}/{id}", new {id = UrlParameter.Optional});// other configuration settings
注意:
當一個route通過MapHttpRoute增加后匹配到一個Request,,HttpControllerRouteHandler會創建一個新的HttpControllerHandler,其繼承自IAsyncHttpHandler,此handler通過RouteData(包含了路由的信息)初始化。
當被調用,HttpControllerhandler 在他的BeginReocessRequest方法里有以下行為:
當這個請求被HttpServer接受后,進入宿主的獨立處理階段(Web API的新管道)
下面的類圖是路由解決過程的摘要,并且分配給HttpServer(消息處理管道)
原文地址:
看文字描述比較晦澀難懂,需要根據源碼理解,上圖容易理解。
HttpApplication -> UrlRoutingModule -> RouteCollection -> RouteData -> HttpControllerRouteHandler -> HttpControllerHandler -> HttpRequestMessage -> HttpServer
附加一些源碼:1、UrlRoutingModule獲取RouteData
public virtual void PostResolveRequestCache(HttpContextBase context){ RouteData routeData = this.RouteCollection.GetRouteData(context); if (routeData == null) { return; } IRouteHandler routeHandler = routeData.RouteHandler; if (routeHandler == null) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.GetString("UrlRoutingModule_NoRouteHandler"), new object[0])); } 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(string.Format(CultureInfo.CurrentUICulture, SR.GetString("UrlRoutingModule_NoHttpHandler"), new object[] { routeHandler.GetType() })); } if (!(httpHandler is UrlAuthFailureHandler)) { context.RemapHandler(httpHandler); return; } if (FormsAuthenticationModule.FormsAuthRequired) { UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this); return; } throw new HttpException(401, SR.GetString("Assess_Denied_Description3"));}View Code
2、MapHttpRoute(RouteCollectionExtension)
public static Route MapHttpRoute(this RouteCollection routes, string name, string routeTemplate, object defaults, object constraints, HttpMessageHandler handler){ if (routes == null) { throw Error.ArgumentNull("routes"); } HttpRouteValueDictionary defaultsDictionary = new HttpRouteValueDictionary(defaults); HttpRouteValueDictionary constraintsDictionary = new HttpRouteValueDictionary(constraints); HostedHttpRoute httpRoute = (HostedHttpRoute)GlobalConfiguration.Configuration.Routes.CreateRoute(routeTemplate, defaultsDictionary, constraintsDictionary, dataTokens: null, handler: handler); Route route = httpRoute.OriginalRoute; routes.Add(name, route); return route;}View Code
3、HttpControllerRouteHandler.GetHandler
protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext){ return new HttpControllerHandler(requestContext.RouteData);}View Code
4、HttpControllerHandler.ProcessRequest
internal async Task ProcessRequestAsyncCore(HttpContextBase contextBase){ HttpRequestMessage request = contextBase.GetHttpRequestMessage() ?? ConvertRequest(contextBase); // Add route data request.SetRouteData(_routeData); CancellationToken cancellationToken = contextBase.Response.GetClientDisconnectedTokenWhenFixed(); HttpResponseMessage response = null; try { response = await _server.SendAsync(request, cancellationToken); await CopyResponseAsync(contextBase, request, response, _exceptionLogger.Value, _exceptionHandler.Value, cancellationToken); } finally { // The other HttpTaskAsyncHandler is HttpRouteExceptionHandler; it has similar cleanup logic. request.DisposeRequestResources(); request.Dispose(); if (response != null) { response.Dispose(); } }}View Code
5、HttpApplication -> HttpControllerHandler
public HttpControllerHandler(RouteData routeData) : this(routeData, GlobalConfiguration.DefaultServer){}public HttpControllerHandler(RouteData routeData, HttpMessageHandler handler){ if (routeData == null) { throw Error.ArgumentNull("routeData"); } if (handler == null) {
新聞熱點
疑難解答