本文共 7483 字,大约阅读时间需要 24 分钟。
我们知道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, IDictionarydefaults, IDictionary constraints, IDictionary 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对象。
那么上述所说的RouteData是什么时候生成呢?
我们再来看看这个Route对象的定义:
当请求过来时请求URL会与注册的路由(Route)进行匹配,若匹配成功,由上知,此时同时会通过GetRouteData方法生成一个 RouteData 对象,我们同时看看该RouteData的定义:
public class RouteData{ // Fields private RouteValueDictionary _dataTokens; private IRouteHandler _routeHandler; private RouteValueDictionary _values; // Methods public RouteData(); public RouteData(RouteBase route, IRouteHandler routeHandler); public string GetRequiredString(string valueName); // Properties public RouteValueDictionary DataTokens { get; } public RouteBase Route { get; set; } public IRouteHandler RouteHandler { get; set; } public RouteValueDictionary Values { get; }}
此对象中有一个匹配路由Route的引用属性,也就是当前匹配成功的Route对象并且还有返回值为IRouteHandler的属性RouteHandler。
所以在注册路由的过程是:
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_instance; [CompilerGenerated] private static Func 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寄宿模式下的消息处理管道给出整体示意图:来自【】
转载地址:http://kuwga.baihongyu.com/