在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
ASP.NET Web API 的核心框架是一个由一组HttpMessageHandler有序组成的双工消息处理管道;寄宿监听到请求接受后,把消息传入该管道经过所有HttpMessageHandler处理后,目标HttpController会被激活,对应Action方法被执行,生成响应消息也会进入管道经过所有HttpMessageHandler处理,处理后消息又流回寄宿,其把响应信息返回给客户端;可以判断出消息处理管道与寄宿是相互独立的,其是一个通过一组HttpMessageHandler对请求和响应进行处理,独立于寄宿的消息处理管道。 简单概括下,请求消息进入消息处理管道时,默认会创建一个HttpServer(继承自DelagatingHandler),作为消息处理管道的头部,其构造函数中指定了HttpConfiguration和Dispatcher,HttpConfiguration中保存了用户自定义的消息处理管道的中间部分的处理器,用户可以把自定义处理器往里边添加,而Dispatcher默认指定了一个HttpRoutingDispatcher类型的HttpMessageHandler,作为消息处理管道的末尾,在执行HttpServer的SendAsync方法时候,会确保消息处理管道创建,即调用了HttpClientFactory.CreatePipeline方法,把HttpConfiguration中的自定义消息处理器集合按添加顺序通过InnerHandler连接起来,并在末尾添加上HttpRoutingDispatcher这个默认指定的管道尾部处理器,然后HttpServer的SendAsync方法会启动管道中的第一个处理器的SendAsync,启动链式调用,直到管道尾部的HttpRoutingDispatcher,其主要功能是路由以及消息分发,路由主要是指其会先从HttpMessagRequest中获取路由数据(Web Host模式下,ASP.NET路由解析后会把路由变量数据放到HttpRequestMessage属性字典中),如果获取不到路由数据,则直接进行路由解析(Self Host模式下),解析到的数据同样要放到HttpRequestMessage属性字典中,消息分派功能是指,在HttpRoutingDispatcher构造函数中指定了一个内部消息处理器HttpControllerDispatcher,其主要完成HttpController激活、Action的执行以及异步执行后响应消息的返回。 一、涉及的类及源码分析 HttpMessageHandler、DelegatingHandler、HttpMessageInvoker、HttpClientFactory在程序集System.Net.Http中,其它类都在System.Web.Http程序集中,主要类和成员如下图:
1、HttpMessageHandler 管道中的一个消息处理器,每个处理器负责单一处理功能,整个消息处理管道就是由一个个这种消息处理器链接而成。 是个抽象类,继承自IDisposable,可以学习下Dispose模式的用法,通用逻辑在抽象类里完成,如Dispose()方法,特殊的资源回收由子类重写实现,只有个核心抽象方法SendAsync也由子类来实现。 public abstract class HttpMessageHandler : IDisposable protected virtual void Dispose(bool disposing) 2、DelegatingHandler 是一个抽象类,继承自HttpMessageHandler,消息处理管道中的每个HttpMessageHandler就是通过该类InnerHandler链接在一起执行的,其保存着通过构造函数传入(或直接设置属性)的下一个HttpMessageHandler,在重写的方法SendAsync中完成自己的逻辑后,调用InnerHandler(下一个HttpMessageHandler)的SendAsync,以此方式重复执行,直到整个链上的消息处理器执行完,HttpMessageHandler链的组装不在这里完成,后边会说明。 这也是设计模式职责链模式的应用。 public abstract class DelegatingHandler : HttpMessageHandler public HttpMessageHandler InnerHandler protected DelegatingHandler() protected DelegatingHandler(HttpMessageHandler innerHandler) //重写的核心方法SendAsync protected internal override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) //确保资源没回收,且innerHandler不为空 protected override void Dispose(bool disposing) //销毁innerHandler private void CheckDisposed() private void CheckDisposedOrStarted() private void SetOperationStarted() //innerHandler 不能为null 3、HttpServer 消息处理管道的第一个消息处理器,继承自DelegatingHandler,其由两个重要属性Configuration和Dispatcher,Configuration属性(HttpConfiguration类型)用于配置整个消息处理管道,可在构造函数中指定,而Dispatcher属性存放了在构造函数中默认创建的HttpRoutingDispatcher,其是消息处理管道的最后一个HttpMessageHandler ,另外,重写了虚方法Dispose,实现了对Configuration的资源回收,HttpConfiguration也实现了IDisposable。 消息处理管道的头和尾都确定了,中间部分是可扩展定制的,HttpConfiguration有个只读属性MessageHandlers,其用来创建整个消息处理管道,即创建一个链式结构,成员是DelegatingHandler,所以自定义的处理器都要继承自DelegatingHandler,而且都要添加进MessageHandlers,互相间通过InnerHandler属性链接起来。 但是,什么时候把这个管道组装起来呢?在HttpServer执行SendAsync方法时,先会调用EnsureInitialized确保消息处理管道已经被创建,之后才会启动管道,链式调用每个处理器,EnsureInitialized方法最后通过 HttpClientFactory.CreatePipeline(_dispatcher, _configuration.MessageHandlers)进行管道创建。由此也可以得出,创建HttpServer实例的时候,管道还没有创建,所以实例化HttpServer对象之后马上往HttpConfiguration的MessageHandlers添加处理器,也是会添加进管道执行的。 public class HttpServer : DelegatingHandler private readonly HttpConfiguration _configuration; private IExceptionLogger _exceptionLogger; public HttpServer() //默认创建了 HttpRoutingDispatcher作为消息处理管道的最后一个HttpMessageHandler public HttpServer(HttpMessageHandler dispatcher) public HttpServer(HttpConfiguration configuration, HttpMessageHandler dispatcher) if (dispatcher == null) IPrincipal principal = Thread.CurrentPrincipal; _dispatcher = dispatcher; //消息管道最后一个处理器 public HttpMessageHandler Dispatcher //应用的全局配置,存放了注册的自定义处理器集合 public HttpConfiguration Configuration //只用于单元测试 return _exceptionLogger; //只用于单元测试 return _exceptionHandler; //释放非托管资源和托管资源(disposing为true) base.Dispose(disposing); //核心方法,先要确保消息处理管道要被创建,才触发消息处理管道处理器依次执行 protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) if (_disposed) //确保管道已经被创建 // 获取当前同步上下文 //将当前同步上下文存放到请求对象中的属性字典中,后续操作需要在此同步上下文中执行,可以从请求对象属性字典中获取 // 将 HttpConfiguration作为一个参数添加到请求对象属性字典中 // 确保有一个principal,如果没有就创建一个匿名的principal // 确保在request context存在一个 principal ,如果存在一个.request context if (requestContext == null) request.SetRequestContext(requestContext); try try //执行方法,启动链式处理器执行 Debug.Assert(exceptionInfo.SourceException != null); ExceptionContext exceptionContext = new ExceptionContext(exceptionInfo.SourceException, if (response == null) return response; private void EnsureInitialized() // 创建管道,见下一个类说明HttpClientFactory的CreatePipeline private static HttpConfiguration EnsureNonNull(HttpConfiguration configuration) return configuration; _configuration.EnsureInitialized()代码如下:
4、HttpClientFactory 静态类根据管道默认指定最后一个处理器以及用户注册的所有处理器你集合来创建消息处理管道,整个管道是把集合里的每个处理器按先后顺序连接起来,并在最后链上默认指定的最后一个处理器 的dispatcher,由此也可以得出,消息处理器的执行顺序也就是添加到 HttpConfiguration的消息处理器集合中的顺序。 public static class HttpClientFactory public static HttpClient Create(HttpMessageHandler innerHandler, params DelegatingHandler[] handlers) //HttpServer调用的创建管道方法 if (handlers == null) HttpMessageHandler pipeline = innerHandler; //先将自定义集合里的处理器倒转顺序 if (handler.InnerHandler != null) //由于倒排了,最后handler.InnerHandler指向的是参数传进来的默认指定的最后一个处理器(非自定义处理器) handler.InnerHandler = pipeline; //由于倒排了,最后pipeline指向的是倒排之前的第一个handler //这样返回的是,把集合里的每个处理器按先后顺序连接起来,并在最后链上默认指定的最后一个处理器 的dispatcher return pipeline; 5、HttpRoutingDispatcher 在HttpServer中默认指定的消息管道的最后一个消息处理器,它继承自HttpMessageHandler而不是DelegatingHandler,它负责HttpController激活和Action的执行,而在构造函数中除了指定HttpConfiguration参数以及一个重要的defaultHandler参数HttpControllerDispatcher(也是继承自HttpMessageHandler),HttpController激活、Action的执行以及后续的操作都是它来执行。 HttpController激活和Action的执行需要路由系统解析出来的路由变量数据,在Web Host模式下,ASP.NET路由系统解析出路由数据后会存放在HttpRequestMessage的属性字典中,所以直接从其中获取就行,如果获取不到,说明可能是Self Host模式,利用路由匹配出路由数据,如果匹配出数据,同时将其数据存放到HttpRequestMessage的属性字典,如果没匹配出路由数据,说明路由匹配不了,直接错误响应。 HttpControllerDispatcher被封装成HttpMessageInvoker,调用其SendAsync(request, cancellationToken)方法。 所以,HttpRoutingDispatcher有两大功能:
public class HttpRoutingDispatcher : HttpMessageHandler public HttpRoutingDispatcher(HttpConfiguration configuration) _configuration = configuration; //HttpControllerDispatcher被封装成HttpMessageInvoker //获取不到,直接解析(Self Host模式) //获取到的话,就设置到从HttpRequestMessage属性字典中 //为空说明路由不匹配,404 Not Found if (routeData == null || (routeData.Route != null && routeData.Route.Handler is StopRoutingHandler)) //删除缺省的(RouteParameter.Optional)路由变量,比较隐蔽的逻辑 routeData.RemoveOptionalRoutingParameters(); var invoker = (routeData.Route == null || routeData.Route.Handler == null) ? 6、HttpMessageInvoker public class HttpMessageInvoker : IDisposable public HttpMessageInvoker(HttpMessageHandler handler) public HttpMessageInvoker(HttpMessageHandler handler, bool disposeHandler) public virtual Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) public void Dispose() protected virtual void Dispose(bool disposing) private void CheckDisposed() 7、HttpControllerDispatcher HttpController激活、Action的执行以及后续的操作最终都是它来执行的,也是继承自HttpMessageHandler,我们可以说它是隶属于HttpRoutingDispatcher的一个HttpMessageHandler,而HttpRoutingDispatcher可以作为消息处理管道的最有一个处理器。 public class HttpControllerDispatcher : HttpMessageHandler private IHttpControllerSelector _controllerSelector; public HttpControllerDispatcher(HttpConfiguration configuration) _configuration = configuration; public HttpConfiguration Configuration private IHttpControllerSelector ControllerSelector return _controllerSelector; //核心方法,里边的细节是控制器的创建及其Action方法执行的细节,放到后边再说 protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) ExceptionDispatchInfo exceptionInfo; try //生成控制器描述符 |
请发表评论