ASP.NET Web API的消息处理管道: HttpRoutingDispatcher
ASP.NET Web API的消息处理管道: HttpRoutingDispatcher
认情况下,作为消息处理管道“龙头”的HttpServer的Dispatcher属性返回一个HttpRoutingDispatcher对象,该对象可以视为这个消息处理管道的最后一个非DelegatingHandler类型的HttpMessageHandler。用户的调用请求一般都是针对定义在某个HttpController中的某个Action方法,所以消息处理管道最终需要激活相应的HttpController并执行对应的Action方法,而这些是通过HttpRoutingDispatcher来完成的。[本文已经同步到《How ASP.NET Web API Works?》]
如下面的代码片断所示,HttpRoutingDispatcher并不是DelegatingHandler的继承者,而是直接继承自HttpMessageHandler。我们在构建一个HttpRoutingDispatcher对象的时候需要指定一个HttpConfiguration对象,而通过参数defaultHandler指定的HttpMessageHandler对于创建的HttpRoutingDispatcher对象来说具有重要的意义,HttpController的激活、Action方法的选择与执行等后续操作实际上是由它来完成的。
1: public class HttpRoutingDispatcher : HttpMessageHandler
2: {
3: public HttpRoutingDispatcher(HttpConfiguration configuration);
4: public HttpRoutingDispatcher(HttpConfiguration configuration, HttpMessageHandler defaultHandler);
5:
6: protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
7: }
ASP.NET Web API消息处理管道不具有一个类似于HttpContext的对象来表示基于当前请求的上下文,但是表示请求消息的HttpRequestMessage对象具有一个通过Properties属性表示的属性字典,我们可以将基于当前上下文的数据或对象添加到当前请求消息的属性字典中。通过对HttpServer的介绍我们知道它会将当前SynchronizationContext和HttpConfiguration添加当前请求消息的属性字典,通过ASP.NET Web API路由系统生成的HttpRouteData或者通过ASP.NET路由系统生成的RouteData转换而成的HttRouteData(针对Web Host寄宿模式)同样以相同的方式保存在当前请求消息中。
保存HttpRouteData对应属性条目的Key为“MS_HttpRouteData”,我们可以通过类型HttpPropertyKeys的静态字段HttpRouteDataKey得到这个Key,也可以直接调用HttpRequestMessage的如下两个扩展方法GetRouteData和SetRouteData进行RouteData的获取和设置。
1: public static class HttpPropertyKeys
2: {
3: //其他成员
4: public static readonly string HttpRouteDataKey;
5: }
6:
7: public static class HttpRequestMessageExtensions
8: {
9: //其他成员
10: public static IHttpRouteData GetRouteData(this HttpRequestMessage request);
11: public static void SetRouteData(this HttpRequestMessage request, IHttpRouteData routeData);
12: }
当HttpRoutingDispatcher的SendAsync方法被执行的时候,它会先判断作为参数的HttpRequestMessage对象的属性字典中的HttpRouteData是否已经存在,如果存在则直接将请求交付给创建时指定的HttpMessageHandler进行处理。如果在通过预定义的Key在请求消息的属性列表中找不到HttpRouteData对象,则直接通过指定的HttpConfiguration的Routes属性得到但前路由表,并将但前请求作为参数调用其GetRouteData方法。如果方法返回一个具体的HttpRouteData对象,则将请求交付给创建时指定的HttpMessageHandler进行后续处理,否则直接返回一个“404, Not Found”响应。
HttpControllerDispatcher
我们从命名可以看出HttpRoutingDispatcher具有两个基本的职能,即“路由(Routing)”和“消息分发(Dispatching)”。对于前者,它会调用当前路由表对请求消息进行解析进而生成用于封装路由数据的HttpRouteData(如果这样的HttpRouteData不存在于当前请求的属性字典中)。对于后者,它会将请求直接分发给在创建时指定的HttpMessageHandler来完成进一步处理。
在默认的情况下(在创建HttpRoutingDispatcher对象的时候在构造函数中没有通过参数具体指定这个HttpMessageHandler)这个从HttpRoutingDispatcher手中接管请求的HttpMessageHandler是一个HttpControllerDispatcher的对象,其成员定义入下所示。HttpControllerDispatcher在整个消息处理管道中显得尤为重要,HttpController的激活、Action方法的执行以及响应消息的生成均是由HttpControllerDispatcher来完成的。
1: public class HttpControllerDispatcher : HttpMessageHandler
2: {
3: public HttpControllerDispatcher(HttpConfiguration configuration);
4: protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
5:
6: public HttpConfiguration Configuration { get; }
7: }

当我们将HttpControllerDispatcher引入后,整个消息处理管道具有了如右图所示的结构。从这个结构来看,貌似HttpControllerDispatcher才是整个消息处理管道的最后一个HttpMessageHandler。这种说法没有错,但我们个人还是倾向于将HttpControllerDispatcher视为“隶属于” HttpRoutingDispatcher的“内部”HttpMessageHandler,所以仍将这个“包含” HttpRoutingDispatcher的HttpRoutingDispatcher视为组成消息处理管道的最后一个HttpMessageHandler。除此之外,“N个DelegagingHandler + 1个HttpMessageHander”这样的链式结构也刚好与基于DelegagingHandler的委托链相匹配。对于读者朋友来说,具体倾向于那种说法并不重要,重要的是能够深刻了解整个消息处理管道的真正构成。
实例演示:揭示HttpRoutingDispatcher的路由功能
为了让读者对实现在HttpRoutingDispatcher中的路由功能(即通过调用路由表对请求消息进行匹配解析并生成HttpRouteData,并将其放入请求消息的属性字典)具有更加深刻的影响,我们来进行一个简单的实例演示来揭示其路由功能的存在。
我们在一个空的ASP.NET MVC应用中定义如下一个MyHttpRoutingDispatcher。MyHttpRoutingDispatcher直接继承自HttpRoutingDispatcher,其SendAsync方法的目的在于将受保护的同名方法“转换”成公有方法以方便后续调用。
1: public class MyHttpRoutingDispatcher : HttpRoutingDispatcher
2: {
3: public MyHttpRoutingDispatcher(HttpConfiguration configuration)
4: : base(configuration)
5: { }
6:
7: public new Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
8: {
9: return base.SendAsync(request, cancellationToken);
10: }
11: }
我们创建了一个具有如下定义的HomeController。在默认的Action方法Index中,我们创建了一个HttpConfiguration,并在其路由表中注册了一个URL模板为“wheather/{areaCode}/{days}”的HttpRoute。然后为创建了一个基于HTTP-GET的HttpRequestMessage,其访问地址(“http://www.artech.com/wheather/010/2”)与注册的URL模板相匹配。接下来我们针对这个HttpConfiguration创建了一个MyHttpRoutingDispatcher对象,并将该HttpRequestMessage对象作为参数调用其SendAsync方法。最后我们直接调用HttpRequestMessage对象的扩展方法GetRouteData获取添加到它属性字典中的HttpRouteData对象,并将保存在Values属性中的路由变量的名称和值输出来。
1: public class HomeController : Controller
2: {
3: public void Index()
4: {
5: HttpConfiguration configuration = new HttpConfiguration();
6: configuration.Routes.MapHttpRoute("default", "wheather/{areaCode}/{days}");
7: HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://www.artech.com/wheather/010/2");
8: MyHttpRoutingDispatcher dispatcher = new MyHttpRoutingDispatcher(configuration);
9: dispatcher.SendAsync(request, new CancellationToken(false));
10: IHttpRouteData routeData = request.GetRouteData();
11: foreach (var item in routeData.Values)
12: {
13: Response.Write(string.Format("{0}: {1}<br/>", item.Key, item.Value));
14: }
15: }
16: }
该程序运行之后会在浏览器中呈现出如右图所示的输出结果,可以看出我们期望的两个路由变量(areaCode和days)被正常输出,而它们正是在HttpRoutingDispatcher的SendAsync方法被执行的时候生成并添加到请求消息之中的。
缺省路由变量的删除
我们在进行路由注册的时候可以为某个路由变量设置一个默认值,这个默认值可以是一个具体的变量值,也可以是通过RouteParameter具有如下定义的静态只读字段Optional返回的一个RouteParameter对象,我们具有这种默认值的路由变量成为缺省路由变量。
1: public sealed class RouteParameter
2: {
3: public static readonly RouteParameter Optional;
4: }
虽然同是具有默认值的路由变量,但是缺省路由变量具有不同之处:如果请求URL中没有提供对应变量的值,普通具有默认值的路由变量依然会出现在最终HttpRouteData的Values属性中,但是缺省路由变量则不会。实际上缺省路由变量的删除是由HttpRoutingDispatcher实现的。在执行SendAsync方法的时候,如果得到的HttpRouteData(可能是预先添加到HttpRequestMessage的属性字典中,也可以是HttpRoutingDispatcher利用ASP.NET Web API路由系统对请求进行解析获得)的Values属性具有值为RouteParameter. Optional的路由变量,它会被直接剔除出去。
ASP.NET Web API的消息处理管道: HttpRoutingDispatcher的更多相关文章
- ASP.NET Web API的消息处理管道:"龙头"HttpServer
ASP.NET Web API的消息处理管道:"龙头"HttpServer 一般来说,对于构成ASP.NET Web API消息处理管道的所有HttpMessageHandler来 ...
- ASP.NET Web API的消息处理管道: Self Host下的消息处理管道[上篇]
ASP.NET Web API的消息处理管道: Self Host下的消息处理管道[上篇] ASP.NET Web API服务端框架核心是一个独立于具体寄宿环境的消息处理管道,它不关心请求消息来源于何 ...
- ASP.NET Web API 2 消息处理管道
Ø 前言 ASP.NET 的应用程序都会有自己的消息处理管道和生命周期,比如:ASP.NET Web 应用程序(Web Form).ASP.NET MVC,还有本文将讨论的 ASP.NET Web ...
- ASP.NET Web API标准的“管道式”设计
ASP.NET Web API的核心框架是一个消息处理管道,这个管道是一组HttpMessageHandler的有序组合.这是一个双工管道,请求消息从一端流入并依次经过所有HttpMessageHan ...
- Web API之消息处理管道
Web API之消息处理管道 前言 MVC有一套请求处理的机制,当然Web API也有自己的一套消息处理管道,该消息处理管道贯穿始终都是通过HttpMessageHandler来完成.我们知道请求信息 ...
- ASP.NET Web API的安全管道
本篇体验ASP.NET Web API的安全管道.这里的安全管道是指在请求和响应过程中所经历的各个组件或进程,比如有IIS,HttpModule,OWIN,WebAPI,等等.在这个管道中大致分两个阶 ...
- Web APi之消息处理管道(五)
前言 MVC有一套请求处理的机制,当然Web API也有自己的一套消息处理管道,该消息处理管道贯穿始终都是通过HttpMessageHandler来完成.我们知道请求信息存在 RequestMessa ...
- ASP.NET Web API标准的“管道式”设计
详见:http://www.cnblogs.com/artech/p/asp-net-web-api-pipeline.html http://www.codeproject.com/Articles ...
- 目标HttpController在ASP.NET Web API中是如何被激活的:目标HttpController的创建
目标HttpController在ASP.NET Web API中是如何被激活的:目标HttpController的创建 通过上面的介绍我们知道利用HttpControllerSelector可以根据 ...
随机推荐
- 【Heritrix基础教程2】Heritrix基本介绍
1.版本号说明 (1)最新的版本号:3.3.0 (2)最新release版本号:3.2.0 (3)重要历史版本号:1.14.4 3.1.0及之前的版本号:http://sourceforge.net/ ...
- Appium Android Bootstrap源码分析之命令解析执行
通过上一篇文章<Appium Android Bootstrap源码分析之控件AndroidElement>我们知道了Appium从pc端发送过来的命令如果是控件相关的话,最终目标控件在b ...
- 纯CSS隔行换色
原文:纯CSS隔行换色 <head> <meta http-equiv="Content-Type" content="text/html; chars ...
- 【Android开发日记】第一个任务Android Service!Service靴+重力感应器+弹出窗口+保持执行
前言: 近期在写一个小程序,需求是手机摇一摇就弹窗出来.第一次使用了Service,学习了两天,实现了Service弹窗,开机启动,Service启动和销毁,Service保持一直执行. 满足了自己的 ...
- outlook 会议室
原文:outlook 会议室 但是,里面的方法只能用于发送普通电子邮件.如果要发起会议之类的特殊邮件的话,可以C#调用Outlook API,自身的API. 创建项目后,为它添加.NET引用:“Mic ...
- 基于Quqrtz.NET 做的任务调度管理工具
基于Quqrtz.NET 做的任务调度管理工具 国庆前,需求让我看了一下任务调度的数据表设计.和之前一样,有100多个字段,p1 ~ p100, 我说这是干嘛啊!按这写,写死去了! 然后在网上搜了一下 ...
- 使用WCF订阅替换轮训
之前因为某些特定岗位的人不知道是不方便还是什么的原因,所以随便做了个独立于所有系统之外的邮件审批服务,功能是那些人在邮件里给待审批单据发个“同意”就自动审批通过,大致分为3部分:第一部分每隔固定时间去 ...
- 处理程序“svc-Integrated”在其模块列表中有一个错误模块“ManagedPipelineHandler”
HTTP 错误 404.3 - Not Found 由于扩展配置问题而无法提供您请求的页面.如果该页面是脚本,请添加处理程序.如果应下载文件,请添加 MIME 映射. 解决办法:以管理员运行命令:C: ...
- IIS7.5下的httpModules设置
部署到IIS7.5上httpModule不起作用了,原来是iis7里面的网站应用程序池使用了默认的“集成模式”,所以所有的http请求处理都托管给了 IIS,web.config里面的配置就不起效了. ...
- MVC 5.1的遭遇:“已添加了具有相同键的项”
ASP.NET MVC 3升级至MVC 5.1的遭遇:“已添加了具有相同键的项” 最近将一个项目从ASP.NET MVC 3升级至刚刚发布的ASP.NET MVC 5.1,升级后发现一个ajax请 ...