HttpMessageHandler管道[上篇]
整个ASP.NET Web API服务端框架采用管道式设计,这个用于“处理请求、响应回复”的管道本质上就是一组HttpMessageHandler的有序组合。这是一个“双向管道”,具有相反方向的请求消息和响应消息同时在这个管道中流动。对于与一个出于中间位置的HttpMessageHandler来说,当前一个HttpMessageHandler完成了对请求的处理之后,会将处理后的请求传递给自己。定义在自身的请求消息处理操作将直接作用于该请求消息之上,一旦处理完毕再将处理后的请求往后传递。对于反方向的响应消息的处理方式与此类似。[本文已经同步到《How ASP.NET Web API Works?》]
目录
一、HttpMessageHandler
二、DelegatingHandler
一、HttpMessageHandler
ASP.NET Web API服务端框架由一组HttpMessageHandler经过“首尾相连”而成,管道式设计使该框架具有很高的扩展性。虽然ASP.NET Web API服务端框架的作用是“处理请求、响应回复”,但是具体采用的处理策略因具体的场景而不同。我们不可能也没有必要创建一个“万能”的处理器来满足所有的请求处理场景,所以倒不如让某个处理器只负责某个单一的消息处理功能。针对具体的应用场景中,我们可以根据具体的消息处理需求来选择所需的处理器并共同组成一个完成的消息处理管道。在这里这个用于完成某个单一消息处理功能的处理器就是HttpMessageHandler。
这里的“消息处理”具有两个层面的含义,既包括针对请求消息的处理,还包括基于响应消息的处理。旨在实现某个单一消息处理功能的HttpMessageHandler直接或者间接继承自具有如下定义的抽象类型HttpMessageHandler。在前面介绍“URL路由”中,我们已经提到过ASP.NET Web API通过类型HttpRequestMessage和HttpResponseMessage分别表示管道处理的请求消息和响应消息,所以对HttpMessageHandler的定义就很好理解了。
1: public abstract class HttpMessageHandler : IDisposable
2: {
3: public void Dispose();
4: protected virtual void Dispose(bool disposing);
5:
6: protected abstract Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
7: }
如上面的代码片断所示,抽象类HttpMessageHandler中仅仅定义了一个唯一的受保护的抽象方法SendAsync,这是一个基于“并行编程(Paralle Programing)”而设计的异步方法。其request参数表示传递给当前HttpMessageHandler用于处理的请求消息,这是一个HttpRequestMessage对象。另一个参数cancellationToken是一个发送取消操作信号的CancellationToken对象,如果读者对.NET中的并行编程具有基本了解的话,相信对这个对象应该很熟悉。
针对请求消息和响应消息的处理同时体现在这个SendAsync方法上。具体来说,针对请求消息的处理直接实现在SendAsync方法中,而针对响应消息的处理则通过其返回值来完成,这是一个类型为Task<HttpResponseMessage>的对象。通过HttpMessageHandler组成的消息处理管道以及请求消息和响应消息在管道中的“流动”基本上可以通过右图体现出来。
抽象类HttpMessageHandler实现了IDisposable接口,它按照“标准”的方式实现Dispose方法。如下面的代码片断所示,调用Dispose方法被调用的时候,并没有执行任何资源回收操作。当我们通过继承这个抽象类自定义HttpMessagHandler的时候,可以通过重写这个受保护的虚方法来完成资源释放的相关操作。
1: public abstract class HttpMessageHandler : IDisposable
2: {
3: //其他操作
4: public void Dispose()
5: {
6: this.Dispose(true);
7: GC.SuppressFinalize(this);
8: }
9:
10: protected virtual void Dispose(bool disposing)
11: {}
12: }
二、DelegatingHandler
我们说ASP.NET Web API整个消息处理管道是通过一组有序的HttpMessagHandler“首尾相连”而成,具体实现“串联”的是通过DelegatingHandler这个类型来完成的。顾名思义,DelegatingHandler具有委托功能,当自己负责的任务完成之后可以委托第三方进行后续的工作。如果这个被委托者也是一个DelegatingHandler,不就可以组成一个委托链了吗?而这个委托链不就是一个个DelegatingHandler组成的消息处理管道吗?
如下面的代码片断所示,DelegatingHandler是一个继承自HttpMessageHandler类的抽象类。上面我们所说的这个被委托的第三方由它的属性InnerHandler表示,对应的类型为HttpMessageHandler(不是DelegatingHandler)。DelegatingHandler重写了定义在其类的抽象方法SendAsync,实际上除了直接调用InnerHandler属性的同名方法之外并没有完成任何实质性的操作。
1: public abstract class DelegatingHandler : HttpMessageHandler
2: {
3: protected internal override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
4: public HttpMessageHandler InnerHandler get; set; }
5: }
正如上面所说,如果ASP.NET Web API的消息处理管道均由DelegatingHandler组成(位于管道尾端的HttpMessageHandler除外),我们就可以根据其InnerHandler对另一个被委托的DelegatingHandler的引用,构成具有如右上图所示的链式结构。