上篇中說到ASP.NET Web API架構在SelfHost環境中管道、路由的一個形态,本篇就來說明一下在WebHost環境中ASP.NET Web API架構中的管道、路由又是哪一種形态。
ASP.NET Web API 開篇介紹示例
ASP.NET Web API 路由對象介紹
ASP.NET Web API 管道模型
ASP.NET Web API selfhost宿主環境中管道、路由
ASP.NET Web API webhost宿主環境中管道、路由
下面将會主要講解路由的注冊執行過程(WebHost環境),對于管道不會去刻意的說明,都會包含在路由的講解中,拆開來說明效果不太好。
HttpRoute->HostedHttpRoute->HttpWebRoute->Route
想要清楚的了解路由的執行過程以及管道的形态,就必須對路由對象熟知,然而在前面的《ASP.NET Web API 路由對象介紹》篇幅中隻是分别的對各個環境下的路由對象類型進行了說明,并沒有說明轉變的過程。
現在就來講解路由對象的“轉變”過程。
示例代碼1-1
1
2
3
4
5
<code> </code><code>protected</code> <code>void</code> <code>Application_Start(</code><code>object</code> <code>sender, EventArgs e)</code>
<code> </code><code>{</code>
<code> </code><code>GlobalConfiguration.Configuration.Routes.MapHttpRoute(</code>
<code> </code><code>"DefaultAPI"</code><code>, </code><code>"api/{controller}/{id}"</code><code>, </code><code>new</code> <code>{ controller=</code><code>"product"</code><code>,id = RouteParameter.Optional });</code>
<code> </code><code>}</code>
示例代碼1-1中是在WebHost環境下進行的路由注冊,根據MapHttpRoute()方法我們轉定義過去應該是一個HttpRouteCollection類型的擴充方法類型HttpRouteCollectionExtensions,既然是HttpRouteCollectionExtensions類型裡的實作那我們就過去看看到底啥情況。
示例代碼1-2
6
7
8
9
10
11
12
13
14
<code>public</code> <code>static</code> <code>IHttpRoute MapHttpRoute(</code><code>this</code> <code>HttpRouteCollection routes, </code><code>string</code> <code>name, </code><code>string</code> <code>routeTemplate, </code><code>object</code> <code>defaults, </code><code>object</code> <code>constraints, HttpMessageHandler handler)</code>
<code> </code><code>if</code> <code>(routes == </code><code>null</code><code>)</code>
<code> </code><code>{</code>
<code> </code><code>throw</code> <code>System.Web.Http.Error.ArgumentNull(</code><code>"routes"</code><code>);</code>
<code> </code><code>}</code>
<code> </code><code>HttpRouteValueDictionary dictionary = </code><code>new</code> <code>HttpRouteValueDictionary(defaults);</code>
<code> </code><code>HttpRouteValueDictionary dictionary2 = </code><code>new</code> <code>HttpRouteValueDictionary(constraints);</code>
<code> </code><code>IDictionary<</code><code>string</code><code>, </code><code>object</code><code>> dataTokens = </code><code>null</code><code>;</code>
<code> </code><code>HttpMessageHandler handler2 = handler;</code>
<code> </code><code>IHttpRoute route = routes.CreateRoute(routeTemplate, dictionary, dictionary2, dataTokens, handler2);</code>
<code> </code><code>routes.Add(name, route);</code>
<code> </code><code>return</code> <code>route;</code>
我們可以看到傳回類型是IHttpRoute,生成則是由HttpRouteCollection類型的執行個體調用其中的CreateRoute()方法來實作,這裡有的朋友要問了,這不是SelfHost中的路由注冊實作方式嗎?回答是對的,隻不過在WebHost中利用多态來實作傳回成其他的類型,接着往下看。
既然都看到了在這裡發生的變化,那說明是有繼承了HttpRouteCollection類型的這麼一個類型然後建立的路由對象。這樣一理就清晰多了,在SelfHost環境中HttpRouteCollection類型是存在于HttpConfiguration類型的對象中,并不單獨使用。而在WebHost中也是。
這個時候我們再回過頭來看一下代碼1-1中的GlobalConfiguration類型中的定義。
示例代碼1-3
<code> </code><code>private</code> <code>static</code> <code>Lazy<HttpConfiguration> _configuration = </code><code>new</code> <code>Lazy<HttpConfiguration>(</code><code>delegate</code> <code>{</code>
<code> </code><code>HttpConfiguration configuration = </code><code>new</code> <code>HttpConfiguration(</code><code>new</code> <code>HostedHttpRouteCollection(RouteTable.Routes));</code>
<code> </code><code>configuration.Services.Replace(</code><code>typeof</code><code>(IAssembliesResolver), </code><code>new</code> <code>WebHostAssembliesResolver());</code>
<code> </code><code>configuration.Services.Replace(</code><code>typeof</code><code>(IHttpControllerTypeResolver), </code><code>new</code> <code>WebHostHttpControllerTypeResolver());</code>
<code> </code><code>configuration.Services.Replace(</code><code>typeof</code><code>(IHostBufferPolicySelector), </code><code>new</code> <code>WebHostBufferPolicySelector());</code>
<code> </code><code>return</code> <code>configuration;</code>
<code> </code><code>});</code>
<code> </code><code>public</code> <code>static</code> <code>HttpConfiguration Configuration</code>
<code> </code><code>get</code>
<code> </code><code>return</code> <code>_configuration.Value;</code>
從代碼1-3中我們可以看到_configuration靜态變量使用了延遲加載,啥意思呢就是下面的那個HttpConfiguration類型的Configuration屬性如果使用了才會去執行個體化,跑偏了這不是重點。
重點是在執行個體化靜态變量_configuration中可以清楚的看到使用了HostedHttpRouteCollection類型的路由集合類型對象作為構造函數參數。可以自行的去看一下HostedHttpRouteCollection的内部結構。
現在再回到建立路由的那會,也就是代碼1-1和代碼1-2中所示的那樣,實際也就是HostedHttpRouteCollection類型在建立路由對象,按照老規矩直接看實作代碼。
示例代碼1-4
<code>public</code> <code>override</code> <code>IHttpRoute CreateRoute(</code><code>string</code> <code>uriTemplate, IDictionary<</code><code>string</code><code>, </code><code>object</code><code>> defaults, IDictionary<</code><code>string</code><code>, </code><code>object</code><code>> constraints, IDictionary<</code><code>string</code><code>, </code><code>object</code><code>> dataTokens, HttpMessageHandler handler)</code>
<code> </code><code>{</code>
<code> </code><code>return</code> <code>new</code> <code>HostedHttpRoute(uriTemplate, defaults, constraints, dataTokens, handler);</code>
<code> </code><code>}</code>
從代碼1-4中可以清楚的看到是傳回的是HostedHttpRoute路由對象,我們可以看一下構造函數,隻有這樣才能知道&ldquo;轉變&rdquo;的過程。
<code> </code><code>public</code> <code>HostedHttpRoute(</code><code>string</code> <code>uriTemplate, IDictionary<</code><code>string</code><code>, </code><code>object</code><code>> defaults, IDictionary<</code><code>string</code><code>, </code><code>object</code><code>> constraints, IDictionary<</code><code>string</code><code>, </code><code>object</code><code>> dataTokens, HttpMessageHandler handler)</code>
<code> </code><code>RouteValueDictionary dictionary = (defaults != </code><code>null</code><code>) ? </code><code>new</code> <code>RouteValueDictionary(defaults) : </code><code>null</code><code>;</code>
<code> </code><code>RouteValueDictionary dictionary2 = (constraints != </code><code>null</code><code>) ? </code><code>new</code> <code>RouteValueDictionary(constraints) : </code><code>null</code><code>;</code>
<code> </code><code>RouteValueDictionary dictionary3 = (dataTokens != </code><code>null</code><code>) ? </code><code>new</code> <code>RouteValueDictionary(dataTokens) : </code><code>null</code><code>;</code>
<code> </code><code>this</code><code>.OriginalRoute = </code><code>new</code> <code>HttpWebRoute(uriTemplate, dictionary, dictionary2, dictionary3, HttpControllerRouteHandler.Instance, </code><code>this</code><code>);</code>
<code> </code><code>this</code><code>.Handler = handler;</code>
<code> </code><code>}</code>
在代碼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
15
16
17
18
19
20
21
22
23
24
25
<code> </code><code>public</code> <code>class</code> <code>WebAPIHttpModule:IHttpModule</code>
<code> </code><code>public</code> <code>void</code> <code>Dispose()</code>
<code> </code><code>throw</code> <code>new</code> <code>NotImplementedException();</code>
<code> </code><code>public</code> <code>void</code> <code>Init(HttpApplication context)</code>
<code> </code><code>context.PostResolveRequestCache += context_PostResolveRequestCache;</code>
<code> </code><code>void</code> <code>context_PostResolveRequestCache(</code><code>object</code> <code>sender, EventArgs e)</code>
<code> </code><code>HttpApplication context = sender </code><code>as</code> <code>HttpApplication;</code>
<code> </code><code>HttpContextWrapper contextWrapper = </code><code>new</code> <code>HttpContextWrapper(context.Context);</code>
<code> </code><code>RouteData routeData = RouteTable.Routes.GetRouteData(contextWrapper);</code>
<code> </code><code>RequestContext requestContext=</code><code>new</code> <code>RequestContext(contextWrapper,routeData);</code>
<code> </code><code>IHttpHandler httpHandler = routeData.RouteHandler.GetHttpHandler(requestContext);</code>
<code> </code><code>IHttpAsyncHandler httpAsyncHandler = httpHandler </code><code>as</code> <code>IHttpAsyncHandler;</code>
<code> </code><code>httpAsyncHandler.BeginProcessRequest(context.Context, </code><code>null</code><code>, </code><code>null</code><code>);</code>
<code> </code><code>}</code>
在代碼1-5中我們可以看到首先是擷取了RouteData對象執行個體,以此擷取RouteHandler,然後根據RequestContext擷取IHttpHandler,再轉換為IHttpAsyncHandler類型的執行個體,然後調用其BeginProcessRequest()方法來執行操作。
上面這段話描述的是上述代碼的執行過程,有的朋友可能會疑問了,怎麼就擷取RouteData了?
這裡我給大家解釋一下,在我們的代碼1-2中,有這樣的代碼:
<code> </code><code>IHttpRoute route = routes.CreateRoute(routeTemplate, dictionary, dictionary2, dataTokens, handler2);</code>
首先我們看第一句,這裡的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()方法:
<code> </code><code>protected</code> <code>virtual</code> <code>IHttpHandler GetHttpHandler(RequestContext requestContext)</code>
<code> </code><code>return</code> <code>new</code> <code>HttpControllerHandler(requestContext.RouteData);</code>
可以看到是由HttpControllerHandler這個對象類型來執行最後的操作,那我們就來看一下這個類型的定義:
<code>public</code> <code>class</code> <code>HttpControllerHandler : IHttpAsyncHandler, IHttpHandler</code>
現在大家明白為什麼要轉成IHttpAsyncHandler了吧,因為如果調用了實作了IHttpHandler接口的函數是會報出異常的,因為在HttpControllerHandler類型中并沒有實作IHttpHandler接口隻是一個空殼,然後我們再看一下HttpControllerHandler類型的靜态構造函數:
圖1

這個_server是Lazy<HttpMessageInvoker>類型,在BeginProcessRequest()方法中會執行SendAsync()以此進入ASP.NET Web API的管道。
下面我們看一下整體的一個示意圖,
圖2
最後對于HttpControllerDispatcher類型在控制器部分講解。
本文轉自jinyuan0829 51CTO部落格,原文連結:http://blog.51cto.com/jinyuan/1536713,如需轉載請自行聯系原作者