標籤:asp.net web api asp.net web api 路由、管道
ASP.NET Web API WebHost宿主環境中管道、路由
前言
上篇中說到ASP.NET Web API架構在SelfHost環境中管道、路由的一個形態,本篇就來說明一下在WebHost環境中ASP.NET Web API架構中的管道、路由又是哪一種形態。
ASP.NET Web API
路由、管道
ASP.NET Web API webhost
宿主環境中管道、路由
下面將會主要講解路由的註冊執行過程(WebHost環境),對於管道不會去刻意的說明,都會包含在路由的講解中,拆開來說明效果不太好。
HttpRoute->HostedHttpRoute->HttpWebRoute->Route
想要清楚的瞭解路由的執行過程以及管道的形態,就必須對路由對象熟知,然而在前面的《ASP.NET Web API 路由對象介紹》篇幅中只是分別的對各個環境下的路由物件類型進行了說明,並沒有說明轉變的過程。
現在就來講解路由對象的“轉變”過程。
範例程式碼1-1
protected void Application_Start(object sender, EventArgs e) { GlobalConfiguration.Configuration.Routes.MapHttpRoute( "DefaultAPI", "api/{controller}/{id}", new { controller="product",id = RouteParameter.Optional }); }
範例程式碼1-1中是在WebHost環境下進行的路由註冊,根據MapHttpRoute()方法我們轉定義過去應該是一個HttpRouteCollection類型的擴充方法類型HttpRouteCollectionExtensions,既然是HttpRouteCollectionExtensions類型裡的實現那我們就過去看看到底啥情況。
範例程式碼1-2
public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints, HttpMessageHandler handler) { if (routes == null) { throw System.Web.Http.Error.ArgumentNull("routes"); } HttpRouteValueDictionary dictionary = new HttpRouteValueDictionary(defaults); HttpRouteValueDictionary dictionary2 = new HttpRouteValueDictionary(constraints); IDictionary<string, object> dataTokens = null; HttpMessageHandler handler2 = handler; IHttpRoute route = routes.CreateRoute(routeTemplate, dictionary, dictionary2, dataTokens, handler2); routes.Add(name, route); return route; }
我們可以看到傳回型別是IHttpRoute,產生則是由HttpRouteCollection類型的執行個體調用其中的CreateRoute()方法來實現,這裡有的朋友要問了,這不是SelfHost中的路由註冊實現方式嗎?回答是對的,只不過在WebHost中利用多態來實現返回成其他的類型,接著往下看。
既然都看到了在這裡發生的變化,那說明是有繼承了HttpRouteCollection類型的這麼一個類型然後建立的路由對象。這樣一理就清晰多了,在SelfHost環境中HttpRouteCollection類型是存在於HttpConfiguration類型的對象中,並不單獨使用。而在WebHost中也是。
這個時候我們再回過頭來看一下代碼1-1中的GlobalConfiguration類型中的定義。
範例程式碼1-3
private static Lazy<HttpConfiguration> _configuration = new Lazy<HttpConfiguration>(delegate { HttpConfiguration configuration = new HttpConfiguration(new HostedHttpRouteCollection(RouteTable.Routes)); configuration.Services.Replace(typeof(IAssembliesResolver), new WebHostAssembliesResolver()); configuration.Services.Replace(typeof(IHttpControllerTypeResolver), new WebHostHttpControllerTypeResolver()); configuration.Services.Replace(typeof(IHostBufferPolicySelector), new WebHostBufferPolicySelector()); return configuration; }); public static HttpConfiguration Configuration { get { return _configuration.Value; } }
從代碼1-3中我們可以看到_configuration靜態變數使用了消極式載入,啥意思呢就是下面的那個HttpConfiguration類型的Configuration屬性如果使用了才會去執行個體化,跑偏了這不是重點。
重點是在執行個體化靜態變數_configuration中可以清楚的看到使用了HostedHttpRouteCollection類型的路由集合類型對象作為建構函式參數。可以自行的去看一下HostedHttpRouteCollection的內部結構。
現在再回到建立路由的那會,也就是代碼1-1和代碼1-2中所示的那樣,實際也就是HostedHttpRouteCollection類型在建立路由對象,按照老規矩直接看實現代碼。
範例程式碼1-4
public override IHttpRoute CreateRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler) { return new HostedHttpRoute(uriTemplate, defaults, constraints, dataTokens, handler); }
從代碼1-4中可以清楚的看到是返回的是HostedHttpRoute路由對象,我們可以看一下建構函式,只有這樣才能知道“轉變”的過程。
public HostedHttpRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler) { RouteValueDictionary dictionary = (defaults != null) ? new RouteValueDictionary(defaults) : null; RouteValueDictionary dictionary2 = (constraints != null) ? new RouteValueDictionary(constraints) : null; RouteValueDictionary dictionary3 = (dataTokens != null) ? new RouteValueDictionary(dataTokens) : null; this.OriginalRoute = new HttpWebRoute(uriTemplate, dictionary, dictionary2, dictionary3, HttpControllerRouteHandler.Instance, this); this.Handler = handler; }
在代碼1-4中我們只需要關注OriginalRoute屬性的賦值,OriginalRoute屬性是HostedHttpRoute類型裡的一個屬性,是用來設定對Route對象的引用,範例程式碼1-4中也就是HttpWebRoute類型的對象,對於HttpWebRoute對象的建構函式這裡就不例舉了。這個時候可以看到是將HttpControllerRouteHandler類型的對象作為Route(HttpWebRoute)對象的RouteHandler(路由處理常式)。
大家都知道ASP.NET Web API架構在WebHost環境中是依賴於ASP.NET的,實則也是通過IHttpModule來進行前期的訊息攔截,下面我們看一下在HttpModule中的代碼(我想應該是這樣的,如果有誤請指點。)
範例程式碼1-5
public class WebAPIHttpModule:IHttpModule { public void Dispose() { throw new NotImplementedException(); } public void Init(HttpApplication context) { context.PostResolveRequestCache += context_PostResolveRequestCache; } void context_PostResolveRequestCache(object sender, EventArgs e) { HttpApplication context = sender as HttpApplication; HttpContextWrapper contextWrapper = new HttpContextWrapper(context.Context); RouteData routeData = RouteTable.Routes.GetRouteData(contextWrapper); RequestContext requestContext=new RequestContext(contextWrapper,routeData); IHttpHandler httpHandler = routeData.RouteHandler.GetHttpHandler(requestContext); IHttpAsyncHandler httpAsyncHandler = httpHandler as IHttpAsyncHandler; httpAsyncHandler.BeginProcessRequest(context.Context, null, null); } }
在代碼1-5中我們可以看到首先是擷取了RouteData對象執行個體,以此擷取RouteHandler,然後根據RequestContext擷取IHttpHandler,再轉換為IHttpAsyncHandler類型的執行個體,然後調用其BeginProcessRequest()方法來執行操作。
上面這段話描述的是上述代碼的執行過程,有的朋友可能會疑問了,怎麼就擷取RouteData了?
這裡我給大家解釋一下,在我們的代碼1-2中,有這樣的代碼:
IHttpRoute route = routes.CreateRoute(routeTemplate, dictionary, dictionary2, dataTokens, handler2); routes.Add(name, route);
首先我們看第一句,這裡的route上面說過了是HostedHttpRoute對象,這裡毫無疑問直接過,然後我們再看第二句,這裡的routes是HostedHttpRouteCollection對象不假,但是這個Add()方法添加的方向不是HostedHttpRouteCollection,而是由我們一開始在GlobalConfiguration類型中說過的RouteTable.Routes,當前環境是什嗎?ASP.NET架構環境對吧!毫無疑問這個Add()方法把上面所說的route(HostedHttpRoute對象)添加到了當前環境的RouteTable.Routes中,有的朋友會問了類型不對。確實是不對的在添加的時候route(HostedHttpRoute對象)會轉換成HttpWebRoute對象,HttpWebRoute對象繼承自Route,可以看前面的篇幅,想必說到這裡大家應該明白了。這裡我就不多說了。
我們接著回到代碼1-5中,在擷取了RouteData之後通過RouteHandler的GetHttphandler()方法擷取IHttpHandler執行個體,在RouteData中的這個RouteHandler毫無疑問就是HttpControllerRouteHandler類型。
我們來看下HttpControllerRouteHandler類型中的GetHttphandler()方法:
protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) { return new HttpControllerHandler(requestContext.RouteData); }
可以看到是由HttpControllerHandler這個物件類型來執行最後的操作,那我們就來看一下這個類型的定義:
public class HttpControllerHandler : IHttpAsyncHandler, IHttpHandler
現在大家明白為什麼要轉成IHttpAsyncHandler了吧,因為如果調用了實現了IHttpHandler介面的函數是會報出異常的,因為在HttpControllerHandler類型中並沒有實現IHttpHandler介面只是一個空殼,然後我們再看一下HttpControllerHandler類型的靜態建構函式:
圖1
650) this.width=650;" src="http://images.cnitblog.com/i/627988/201408/052011458349197.png" width="730" height="225" border="0" hspace="0" vspace="0" title="" style="width:730px;height:225px;" />
這個_server是Lazy<HttpMessageInvoker>類型,在BeginProcessRequest()方法中會執行SendAsync()以此進入ASP.NET Web API的管道。
下面我們看一下整體的一個,
圖2
650) this.width=650;" src="http://images.cnitblog.com/i/627988/201408/052012217099124.png" />
最後對於HttpControllerDispatcher類型在控制器部分講解。
本文出自 “金源” 部落格,請務必保留此出處http://jinyuan.blog.51cto.com/8854733/1536713