上篇中说到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,如需转载请自行联系原作者