上篇中说到ASP.NET Web API框架在SelfHost环境中管道、路由的一个形态,本篇就来讲明一下在WebHost环境中ASP.NET Web API框架中的管道、路由又是哪种形态。web
下面将会主要讲解路由的注册执行过程(WebHost环境),对于管道不会去刻意的说明,都会包含在路由的讲解中,拆开来讲明效果不太好。api
HttpRoute->HostedHttpRoute->HttpWebRoute->Routeapp
想要清楚的了解路由的执行过程以及管道的形态,就必须对路由对象熟知,然而在前面的《ASP.NET Web API 路由对象介绍》篇幅中只是分别的对各个环境下的路由对象类型进行了说明,并无说明转变的过程。框架
如今就来说解路由对象的“转变”过程。ide
示例代码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类型里的实现那咱们就过去看看到底啥状况。this
示例代码1-2spa
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中利用多态来实现返回成其余的类型,接着往下看。code
既然都看到了在这里发生的变化,那说明是有继承了HttpRouteCollection类型的这么一个类型而后建立的路由对象。这样一理就清晰多了,在SelfHost环境中HttpRouteCollection类型是存在于HttpConfiguration类型的对象中,并不单独使用。而在WebHost中也是。server
这个时候咱们再回过头来看一下代码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
这个_server是Lazy<HttpMessageInvoker>类型,在BeginProcessRequest()方法中会执行SendAsync()以此进入ASP.NET Web API的管道。
下面咱们看一下总体的一个示意图,
图2
最后对于HttpControllerDispatcher类型在控制器部分讲解。
做者:金源
出处:http://www.cnblogs.com/jin-yuan/
本文版权归做者和博客园共有,欢迎转载,但未经做者赞成必须保留此段声明,且在文章页面