Web API之消息处理管道

前言

MVC有一套请求处理的机制,当然Web API也有自己的一套消息处理管道,该消息处理管道贯穿始终都是通过HttpMessageHandler来完成。我们知道请求信息存在 RequestMessage 中,而响应信息则存在 ResponseMessage 中,当请求信息进入到管道中,此时HttpMessageHandler会对此进行相应的处理,当执行到控制器上的方法时此时就会进行响应,生成的响应信息HttpResponseMessage就会逆向通过HttpMessageHandler依次进行处理最终返回给客户端。下面就请求管道中的对象进行详细叙述。(若有不妥之处,请海涵)。

HttpMessageHandler

此类是所有管道处理中所有对象的基类,也就是说是最重要的一个类,下面我们借助.NET Reflector打开来看看该类的定义

该类是一个抽象类并且其中最重要的两个方法是 Dispose 和 SendAsyc ,对于Dispose方法的实现,我们查看如下:

public void Dispose()
{
this.Dispose(1);
GC.SuppressFinalize(this);
return;
} protected virtual void Dispose(bool disposing)
{
}

就是个非常标准的实现资源回收的方法,但是其并未实现某个资源的回收,下面会用到,先搁置在这里。

对于第二个方法是SendAsync,看到此方法的第一个参数为HttpRequestMessage,我们能想到此方法是用来处理传递进来的请求并返回Task<HttpResponMessage>对象来响应信息,至于第二个参数是与线程有关,通知取消某个操作请参看【CancellationToken】。

DelegatingHandler

经过如上描述,对于请求和响应都是通过HttpMessageHandler来实现,这就相当于是首尾相连,但是真正实现其相连的角色而是DelegateHandler,并且该类并非仅仅是继承,而且还进行了相应的一些扩展,下面我们来看看该类的定义:

上述重要的两个方法 Dispose 和 SendAsync 以及 InnerHandler 字段,下面我们一一来看这三者。

第一个是Dispose,上述已经讲过在HttpMessageHandler中并未实现对资源的回收,从这里我们可以看出它对其进行了重写,说明可能是在其继承类DelegatingHandler中进行了资源回收,只是猜测,我们查看其具体实现就明了了。如下:

protected override void Dispose(bool disposing)
{
if (disposing == null)
{
goto Label_0029;
}
if (this.disposed != null)
{
goto Label_0029;
}
this.disposed = 1;
if (this.innerHandler == null)
{
goto Label_0029;
}
this.innerHandler.Dispose();
Label_0029:
base.Dispose(disposing);
return;
}

很显然,通过 this.Handler.Dispose(); 我们知道是实现了资源回收了的,那这个 InnerHandler 字段到底是干嘛的了,看其返回类型为HttpMessageHandler,说明是获得了HttpMessageHandler对象的引用,接着就是重写基类中的SendAsync方法,而调用此方法正是通过属性InnerHandler来调用。我们说过InnerHandler是获得对象HttpMessageHandler的引用说的更加明确就是下一个HttpMessageHandler处理程序的引用。

通过以上叙述,DelegatingHandler就是串联着整个消息处理管道,因为当前DelegatingHandler处理当前请求完成后,下一个则通过委托给HttpMessageHandler而其引用则交给InnerHandler来进行处理,则整个管道都是依托于DelegatingHandler来实现,整个过程可已将其看成是一个委托链来完成,同时命名为DelegatingHandler表面意思为委托处理这样更贴切的表达了整个过程。但是我们也应该注意到DelegatingHandler中的InnerHandler始终引用了下一个请求的处理,因为在管道中的最后一个处理程序即末尾处理程序中没有下一个处理程序,所以在最后一个处理程序中不会继承DelegatingHandler,而是继承于基类HttpMessageHandler。

对于InnerHandler的实现连接下一个HttpMessageHandler似的委托链,类似如下:

        public IEnumerable<string> GetHandlerChain(DelegatingHandler handler)
{
yield return handler.GetType().Name;
while (null != handler.InnerHandler)
{
yield return handler.InnerHandler.GetType().Name;
handler = handler.InnerHandler as DelegatingHandler;
if (null == handler)
{
break;
}
}
}

HttpServer

上面我们已经讲过除了位于末尾的处理程序是基于HttpMessageHandler外,其余的都是基于DelegatingHandler。同时我们也讲过在整个管道中由InnerHandler连接着下一个HttpMessageHandler,也就是InnerHandler处于整个管道的中间,但是管道头和管道尾是哪个对象呢?管道头就是我们接下来要讲的HttpServer对象,既然该类也是处于整个管道中,则也继承于DelegatingHandler,下面我们来看看该类的定义:

通过上述知HttpServer类确确实实继承于DelegatingHandler中并且最重要的两个属性是 Configuration 和 Dispatcher ,同时这两个属性是只读的,通过查看如下知:

public HttpConfiguration Configuration
{
get
{
return this._configuration;
}
} public HttpMessageHandler Dispatcher
{
get
{
return this._dispatcher;
}
}

HttpServer类中构造函数有几个,当显式指定了上述两个属性的值则会在相应的构造函数中进行初始化,但是如果未指定两个属性的值毫无疑问则会调用默认构造函数,此时则会创建一个HttpConfiguraion作为属性Configuration的值,通过默认构造函数可得知,如下:

public HttpServer()
{
this..ctor(new HttpConfiguration());
return;
}

此时属性Dispatcher的值则是一个 HttpRoutingDispatcher 对象,(该类为管道中的尾,下面会讲)因为该属性的返回值为HttpMessageHandler而HttpRoutingDispatcher类继承于HttpMessageHandler。当HttpServer被创建后,同时此时管道中的头和尾就相继被确定了下来。从在Web API的配置文件中得知,一切配置都是基于HttpConfiguration,所以如果想在管道中自定义处理程序也就是继承于DelegatingHandler,此时进行注册该自定义处理程序当然也就得经过HttpConfiguration来实现。

HttpRoutingDispatcher

上述也对该类做了一点铺垫,此类为管道中的尾即管道中最后一个HttpMessageHandler,同时该类的对象是通过HttpSever即管道中的头的构造函数而生成。此类的定义如下:

public class HttpRoutingDispatcher : HttpMessageHandler
{
// Fields
private readonly HttpConfiguration _configuration;
private readonly HttpMessageInvoker _defaultInvoker; // Methods
public HttpRoutingDispatcher(HttpConfiguration configuration);
public HttpRoutingDispatcher(HttpConfiguration configuration, HttpMessageHandler defaultHandler);
private static void RemoveOptionalRoutingParameters(IDictionary<string, object> routeValueDictionary);
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
}

通过上述此类的定义也验证了作为管道中的尾是继承HttpMessageHandler而非继承于DelegatingHandler,因为当Web API请求的URI是直接请求控制器上的方法,当执行完控制器上的方法时就得作出响应,而HttpRoutingDispatcher作为管道中的最后一个HttpMessageHandler,所以此时要找到控制器并激活控制器上的方法然后逆向通过管道作出响应。通过上述构造函数知,当构建HttpRoutingDispatcher对象时需要指定一个HttpConfigutaion对象,通过上述defaultHandler指定的HttpMessageHandler创建的HttpRoutingDispatcher对象就是为了激活控制器以及方法。

上述就大概介绍了Web API中整个消息管道中几个重要对象:

管道头(HttpServer)、管道中间(DelegatingHandler中的InnerHandler)、管道尾(HttpRoutingDispatcher)。

下面给出一张整个管道的大概示意图。【来源:Web API管道

总结

本节对Web API的核心之一消息处理管道做了一个稍微详细的介绍,个人觉得对消息管道原理做一个基本的了解是必须的,当需要在手动定制在各个管道时期的请求时才不至于手足无措,希望通过比较详细的介绍能够帮助到大家。

Web API之消息处理管道的更多相关文章

  1. ASP.NET Web API的消息处理管道: Self Host下的消息处理管道[上篇]

    ASP.NET Web API的消息处理管道: Self Host下的消息处理管道[上篇] ASP.NET Web API服务端框架核心是一个独立于具体寄宿环境的消息处理管道,它不关心请求消息来源于何 ...

  2. ASP.NET Web API的消息处理管道: HttpRoutingDispatcher

    ASP.NET Web API的消息处理管道: HttpRoutingDispatcher 认情况下,作为消息处理管道“龙头”的HttpServer的Dispatcher属性返回一个HttpRouti ...

  3. ASP.NET Web API的消息处理管道:"龙头"HttpServer

    ASP.NET Web API的消息处理管道:"龙头"HttpServer 一般来说,对于构成ASP.NET Web API消息处理管道的所有HttpMessageHandler来 ...

  4. Web APi之消息处理管道(五)

    前言 MVC有一套请求处理的机制,当然Web API也有自己的一套消息处理管道,该消息处理管道贯穿始终都是通过HttpMessageHandler来完成.我们知道请求信息存在 RequestMessa ...

  5. ASP.NET Web API 2 消息处理管道

    Ø  前言 ASP.NET 的应用程序都会有自己的消息处理管道和生命周期,比如:ASP.NET Web 应用程序(Web Form).ASP.NET MVC,还有本文将讨论的 ASP.NET Web ...

  6. ASP.NET Web API标准的“管道式”设计

    ASP.NET Web API的核心框架是一个消息处理管道,这个管道是一组HttpMessageHandler的有序组合.这是一个双工管道,请求消息从一端流入并依次经过所有HttpMessageHan ...

  7. ASP.NET Web API的安全管道

    本篇体验ASP.NET Web API的安全管道.这里的安全管道是指在请求和响应过程中所经历的各个组件或进程,比如有IIS,HttpModule,OWIN,WebAPI,等等.在这个管道中大致分两个阶 ...

  8. ASP.NET Web API标准的“管道式”设计

    详见:http://www.cnblogs.com/artech/p/asp-net-web-api-pipeline.html http://www.codeproject.com/Articles ...

  9. ASP.NET Web API消息处理管道:Self Host下的消息处理管道[下篇]

    ASP.NET Web API消息处理管道:Self Host下的消息处理管道[下篇] 我们知道ASP.NET Web API借助于HttpSelfHostServer以Self Host模式寄宿于当 ...

随机推荐

  1. windows phone (24) Canvas元素A

    原文:windows phone (24) Canvas元素A Canvas元素表示定制一个区域,并可以通过相对坐标定义子元素位置,在一下情况下Canvas是不可见的 Height 属性等于 0. W ...

  2. 小技巧,把execl.exe转换成dll

    小技巧 把execl.exe转换成dll1.把excel.exe复制到CProgram FilesMicrosoft Visual Studio .NET 2003SDKv1.1Bin夹中,和TlbI ...

  3. hadoop namenode -format Couldn&#39;tload main class &quot;-Djava.library.path=.home.hadoop.hadoop-2.5.2.lib&quot;

    <pre name="code" class="sql">[hadoop@MasterHadoop50 ~]$ hadoop namenode -f ...

  4. QQ旅程server分析01-网关server

    网关server网络进程: s1.连接网关管理器 s2.上报自身信息给网关管理器 s3.从网关管理器获取自己的管理信息 *s4.依照管理信息预分配好须要的资源 s5.网关server打开client监 ...

  5. Cstyle的UEFI导读:第20.0篇 IGD OpRegion interface &amp;&amp; IGD OpRegion PROTOCOL

        ACPI IGD OpRegion interface是用SCI来实现IGD driver,OS,BIOS之间沟通的桥梁,IGD OpRegion PROTOCOL是UEFI BIOS构建桥梁 ...

  6. PM俱乐部之旅7-弱活着

     有些人认为,最终我们放松一点时间,有意想不到的事情发生--公司组织结构调整. 公司由于业务范围调整,所以要进行对应的组织结构调整.PMO部门也随之重组,项目经理俱乐部的活动改成项目交流会,请项目 ...

  7. 【从翻译mos文章】Weblogic AdminServer 启动fail,报错&quot;unable to get file lock, will retry&quot;

    Weblogic AdminServer 启动fail,报错"unable to get file lock, will retry" 参考原始: Weblogic AdminSe ...

  8. Codeforces Round #258 (Div. 2) B. Sort the Array

    题目链接:http://codeforces.com/contest/451/problem/B 思路:首先找下降段的个数,假设下降段是大于等于2的,那么就直接输出no,假设下降段的个数为1,那么就把 ...

  9. 基于ICSharpCode.SharpZipLib.Zip的压缩解压缩

    原文:基于ICSharpCode.SharpZipLib.Zip的压缩解压缩 今天记压缩解压缩的使用,是基于开源项目ICSharpCode.SharpZipLib.Zip的使用. 一.压缩: /// ...

  10. 使用BackgroundWorker组件进行异步操作编程

    本文介绍了BackgroundWorker组件的功能及在基于事件的异步操作编程中的应用,并对组件的实现原理进行简述.在应用程序中,可能会遇到一些执行耗时的功能操作,比如数据下载.复杂计算及数据库事务等 ...