标签:
我们知道Web API本身是无法提供请求-响应的机制,它是通过Web Host以及Self Host的寄宿的宿主方式来提供一个请求-响应的运行环境。二者都是将请求和响应抽象成HttpResponseMessage和HttpRequesMessage对象,并将请求HttpRequestMessage传入到HttpMessageHandler进行处理最终将响应通过HttpResponseMessage逆向通过HttpMessageHandler返回到客户端,但是在其过程中,此二者在管道中的机制是不一样的,由于在最新Web API中是以Web Host寄宿实现,所以仅本节仅讨论Web Host寄宿的实现。
Web API采用Web Host寄宿模式,其路由系统最终还是通过ASP.NET的路由系统来实现,也就是说其本质是将ASP.NET应用程序作为Web API的宿主,利用ASP.NET自身的路由系统并结合IIS来实现去持续监听以及请求和响应的问题。
通过上述叙述知,Web API利用Web Host作为寄宿则利用UrlRoutingModel来动态映射给HttpContext中的HttpHandler是实现管道集成的核心,它会将ASP.NET中的HttpRequest对象表示的请求转换成HttpRequestMessage对象并传入到消息管道中,并将输出的HttpResponseMessage写入到HttpResponse中并最终进行响应输出。现在最主要的问题是这个HttpHandler在Web Host模式下是怎样实现的?请继续往下看。
当通过Web API的配置文件通过模板以及约束等注册一个HttpRoute路由对象到路由集合中时也就是将其注册到路由表中(因为路由表中的属性Routes存着注册的路由的路由集合),首先会创建一个HostedHttpRoute对象,我们看看该对象的定义:
其中最重要的是OriginalRoute属性,照定义来看就仅仅是创建了这个对象而已,确确实实是这样,因为该对象仅仅是起一个过渡作用,因为真正创建的对象是HttpWebRoute的Route对象,通过查看其构造函数可知,如下:
public HostedHttpRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler) { RouteValueDictionary dictionary; RouteValueDictionary dictionary2; RouteValueDictionary dictionary3; base..ctor(); dictionary = (defaults != null) ? new RouteValueDictionary(defaults) : null; dictionary2 = (constraints != null) ? new RouteValueDictionary(constraints) : null; dictionary3 = (dataTokens != null) ? new RouteValueDictionary(dataTokens) : null; this.OriginalRoute = new HttpWebRoute(uriTemplate, dictionary, dictionary2, dictionary3, HttpControllerRouteHandler.Instance, this); this.Handler = handler; return; }
如上红色标记,此时将属性OriginalRoute作为HttpWebRoute对象的引用存在HostedHttpRoute中并返回一个Route对象。所以在注册路由的过程是:
HttpRoute-------------->HostedHttpRoute-------------->HttpWebRoute------------->Route
在HttpWebRoute继承自Route类中有一个属性RouteHandler如下:
public IRouteHandler RouteHandler { [CompilerGenerated] get; [CompilerGenerated] set; }
我们通过如下HttpControllerRouteHandler的定义知,上述RouteHandler就是一个HttpControllerRouteHandler对象,因为HttpControllerRouteHandler实现了接口IRouteHandler,如下:
public class HttpControllerRouteHandler : IRouteHandler { // Fields private static readonly Lazy<HttpControllerRouteHandler> _instance; [CompilerGenerated] private static Func<HttpControllerRouteHandler> CS$<>9__CachedAnonymousMethodDelegate1; // Methods static HttpControllerRouteHandler(); protected HttpControllerRouteHandler(); [CompilerGenerated] private static HttpControllerRouteHandler <.cctor>b__0(); protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext); IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext); // Properties public static HttpControllerRouteHandler Instance { get; } }
注意上述标记,通过GetHttpHandler方法知,在ASP.NET路由中的HttpHandler就是由HttpControllerRouteHandler对象提供的,同时我们看下该方法的定义:
protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) { return new HttpControllerHandler(requestContext.RouteData); }
看见这个方法的返回值没,又涉及到一个对象,其实通过HttpControllerRouteHandler中的方法获得的HttpHandler其实是一个HttpControllerHandler对象,而整个消息处理管道则是有它来创建的。请继续往下看!
上面说过此对象是Web Host寄宿模式下的整个管道的执行者,下面我们就来看看这个类的定义(操蛋,太长了还是就看下这个类的继承,再叙述其他的再给代码):
public class HttpControllerHandler : HttpTaskAsyncHandler { }
再看下其父类的定义:
public abstract class HttpTaskAsyncHandler : IHttpAsyncHandler, IHttpHandler { // Methods protected HttpTaskAsyncHandler(); [EditorBrowsable(EditorBrowsableState.Never)] public virtual void ProcessRequest(HttpContext context); public abstract Task ProcessRequestAsync(HttpContext context); IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData); void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result); // Properties public virtual bool IsReusable { get; } }
简单叙述下,HttpRouteHandler是HttpTaskAsyncHadler的子类,并且其父类为实现了IHttpAsync和IHttpHandler接口的抽象类。最主要的是HttpTaskAsyncHandler调用了实现IHttpAsyncHandler接口的BeginProcessRequest方法,并返回一个IAsyncResult,而EndProcessRequest方法则用来执行了返回值为IAsyncResult的BeginProcessRequest方法。
我们再来看看HttpRouteHandler的一个构造函数:
public HttpControllerHandler(RouteData routeData, HttpMessageHandler handler);
该构造函数的第一个参数就是根据路由解析得到的路由数据,第二个参数就是管道中的处理程序,实质上就是第一个HttpMessageHandler即管道头(HttpServer)。
下面我们总结下在ASP.NET路由系统中HttpControllerHandler被创建的整个过程。请看!
下面我们实现IHttpModel接口并对照上述叙述进行编码,如下:
public class WebHost : IHttpModule { public void Dispose() { throw new NotImplementedException(); } public void Init(HttpApplication context) { context.PostResolveRequestCache += context_PostResolveRequestCache; } void context_PostResolveRequestCache(object sender, EventArgs e) { var app = sender as HttpApplication; var contextWrapper = new HttpContextWrapper(app.Context); var routeData = RouteTable.Routes.GetRouteData(contextWrapper); var requestContext = new RequestContext(contextWrapper, routeData); var httpHandler = routeData.RouteHandler.GetHttpHandler(requestContext); var httpAsyncHandler = httpHandler as IHttpAsyncHandler; httpAsyncHandler.BeginProcessRequest(app.Context, null, null); } }
下面就Web API中Web Host寄宿模式下的消息处理管道给出整体示意图:来自【Web Host管道】
标签:
原文地址:http://www.cnblogs.com/Leo_wl/p/4836948.html