ASP.NET Web API实践系列05,消息处理管道
ASP.NET Web API的消息处理管道可以理解为请求到达Controller之前、Controller返回响应之后的处理机制。之所以需要了解消息处理管道,是因为我们可以借助它来实现对请求和响应的自定义处理。所有的请求被封装到HttpRequestMessage这个类中,所有的响应被封装到HttpResponseMessage这个类中。
既然消息处理管道是可扩展的,那么,ASP.NET Web API一定为我们准备了便于扩展的接口或抽象类,它就是HttpMessageHandler抽象类。
namespace System.Net.Http{public abstract class HttpMessageHandler : IDisposable{protected HttpMessageHandler(){}protected internal abstract Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);protected virtual void Dispose(bool disposing){}public void Dispose(){this.Dispose(true);GC.SuppressFinalize((object)this);}}}
这个抽象基类,把处理请求响应交给了SendAsync方法,而且是以异步的方式处理的。既然这里没有提供SendAsync方法的具体实现,所以HttpMessageHandler抽象类一定有一个派生类,它就是DelegatingHandler类。
public abstract class DelegatingHandler : HttpMessageHandler{private HttpMessageHandler innerHandler;protected DelegatingHandler(HttpMessageHandler innerHandler){this.innerHandler = innerHandler;}public HttpMessageHandler InnerHandler{get{return this.innerHandler;}set{...this.innerHandler = value;}}protected internal override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken){if(request == null){throw new ArgumentNullException("request");}...return this.innerHandler.SendAsync(request, cancellationToken);}}
比较有意思的是,DelegatingHandler本身是一个HttpMessageHandler类型,却还在它的构造函数中注入一个HttpMessageHandler类型,并且在SendAsync方法中,让注入的HttpMessageHandler类型执行SendAsync方法,这形成了一个HttpMessageHandler类型的链条。从这点来说,消息处理管道并不是只有一个人在战斗,而是,只要派生于DelegatingHandler这个类,不管是内置的,还是自定义的,都可以对请求响应作处理。
而在消息处理管道中肯定有一个打头阵的人,这个人就是HttpServer类。
public class HttpServer : DelegatingHandler{public HttpConfiguration Configuration{get;}public HttpMessageHandler Dispatcher{get;}public HttpServer();public HttpServer(HttpMessageHandler dipatcher);public HttpServer(HttpConfiguration configuration);public HttpServer(HttpConfiguration configuration, HttpMessageHandler dispatcher);protected overrde void Dispose(bool disposing); //处理HttpConfiguration对象,因为该对象实现了IDisposable接口protected virutal void Initialize();protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cacellationToken);//别忘了,HttpServer的父类DelegatingHandler还有一个InnerHandler属性。}
这里的HttpServer当然是可以实例化的,每一次实例化意味着创建了HttpMessageHandler类型的链条的头,就是HttpServer本身,也创建了链条的尾,就是Dispatcher属性所表示的HttpMessageHandler类型。
HttpConfiguration又是什么呢?
public class HttpConfiguration : IDisposable{...public Collection<DelegatingHandler> MessageHandlers{get;}}
原来,我们可以从HttpConfiguration的MessageHandlers属性中获取所有的HttpMessageHandler类型,当然也可以把自定义的HttpMessageHandler类型注册到这个MessageHandlers集合中去。
到这,已经蠢蠢欲动,跃跃欲试了,自定义DelegatingHandler可以登场了!大致是:
HttpServer→自定义DelegatingHandler→HttpControllerDispatcher
举例:重新设置HttpRequestMessage.Method属性
一般情况下,客户端,比如浏览器可以发出GET、POST、HEAD、PUT、DELETE请求,当请求进入消息处理管道,我们可以通过HttpRequestMessage.Method属性获取到这些动作类型。但有些客户端却只能发出GET、POST请求中,诸如HEAD、PUT、DELETE等请求必须放到请求报文的X-HTTP-Method-Override属性中,在这种情况下,我们需要把X-HTTP-Method-Override属性值赋值给HttpRequestMessage.Method属性。
创建一个ASP.NET MVC4项目,选择ASP.NET Web API模版,就如"ASP.NET Web API实践系列02,在MVC4下的一个实例, 包含EF Code First,依赖注入, Bootstrap等"中一样。
自定义一个派生于DelegatingHandler的类。
using System;using System.Linq;using System.Net.Http;using System.Threading;using System.Threading.Tasks;namespace ControlAndRoute.Extension{public class MethodOverrideHandler : DelegatingHandler{private readonly string[] _methods = {"DELETE", "HEAD", "PUT"};private const string _header = "X-HTTP-Method-Override";protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken){if (request.Method == HttpMethod.Post && request.Headers.Contains(_header)){//从请求头中获取X-HTTP-Method-Override的属性值var method = request.Headers.GetValues(_header).FirstOrDefault();if (_methods.Contains(method, StringComparer.InvariantCultureIgnoreCase)){request.Method = new HttpMethod(method);}}return base.SendAsync(request, cancellationToken);}}}
在App_Start文件夹下的WebApiConfig类中注册MethodOverrideHandler类。
using System.Web.Http;using ControlAndRoute.Extension;namespace ControlAndRoute{public static class WebApiConfig{public static void Register(HttpConfiguration config){//注册自定义的DelegatingHandlerconfig.MessageHandlers.Add(new MethodOverrideHandler());config.Routes.MapHttpRoute(name: "DefaultApi",routeTemplate: "api/{controller}/{id}",defaults: new { id = RouteParameter.Optional });// 取消注释下面的代码行可对具有 IQueryable 或 IQueryable<T> 返回类型的操作启用查询支持。// 若要避免处理意外查询或恶意查询,请使用 QueryableAttribute 上的验证设置来验证传入查询。// 有关详细信息,请访问 http://go.microsoft.com/fwlink/?LinkId=279712。//config.EnableQuerySupport();// 若要在应用程序中禁用跟踪,请注释掉或删除以下代码行// 有关详细信息,请参阅: http://www.asp.net/web-apiconfig.EnableSystemDiagnosticsTracing();}}}
在ValuesController中public void Put(int id, [FromBody]string value)的方法体内打上断点。打开Fiddler,输入如下:

发出的Put请求,被消息处理管道接收、处理,程序停在Put方法内的断点处。

ASP.NET Web API实践系列05,消息处理管道的更多相关文章
- ASP.NET Web API实践系列04,通过Route等特性设置路由
ASP.NET Web API路由,简单来说,就是把客户端请求映射到对应的Action上的过程.在"ASP.NET Web API实践系列03,路由模版, 路由惯例, 路由设置"一 ...
- ASP.NET Web API实践系列07,获取数据, 使用Ninject实现依赖倒置,使用Knockout实现页面元素和视图模型的双向绑定
本篇接着上一篇"ASP.NET Web API实践系列06, 在ASP.NET MVC 4 基础上增加使用ASP.NET WEB API",尝试获取数据. 在Models文件夹下创 ...
- ASP.NET Web API实践系列09,在Fiddler和控制台中模拟GET和POST请求
ASP.NET Web API本质是由一个进程托管的一组类,需要宿主,这个宿主可以是ASP.NET应用程序,可以是MVC项目,可以是控制台应用程序,也可以是自己定制的宿主. 在VS2012中创建一个& ...
- ASP.NET Web API实践系列06, 在ASP.NET MVC 4 基础上增加使用ASP.NET WEB API
本篇尝试在现有的ASP.NET MVC 4 项目上增加使用ASP.NET Web API. 新建项目,选择"ASP.NET MVC 4 Web应用程序". 选择"基本&q ...
- ASP.NET Web API实践系列03,路由模版, 路由惯例, 路由设置
ASP.NET Web API的路由和ASP.NET MVC相似,也是把路由放在RouteTable中的.可以在App_Start文件夹中的WebApiConfig.cs中设置路由模版.默认的路由模版 ...
- ASP.NET Web API实践系列02,在MVC4下的一个实例, 包含EF Code First,依赖注入, Bootstrap等
本篇体验在MVC4下,实现一个对Book信息的管理,包括增删查等,用到了EF Code First, 使用Unity进行依赖注入,前端使用Bootstrap美化.先上最终效果: →创建一个MVC4项目 ...
- ASP.NET Web API实践系列01,以ASP.NET Web Form方式寄宿
创建一个空的ASP.NET Web Form项目. 右键项目,添加新项,创建Web API控制器类,TestController. 删除掉TestController默认的内容,编写如下: using ...
- ASP.NET Web API实践系列11,如何设计出优秀的API
本篇摘自:InfoQ的微信公众号 在设计API的时候考虑的问题包括:API所使用的传输协议.支持的消息格式.接口的控制.名称.关联.次序,等等.我们很难始终作出正确的决策,很可能是在多次犯错之后,并从 ...
- ASP.NET Web API 2系列(三):查看WebAPI接口的详细说明及测试接口
引言 前边两篇博客介绍了Web API的基本框架以及路由配置,这篇博客主要解决在前后端分离项目中,为前端人员提供详细接口说明的问题,主要是通过修改WebApi HelpPage相关代码和添加WebAp ...
随机推荐
- cancel_delayed_work和flush_scheduled_work【转】
转自:http://blog.chinaunix.net/uid-9688646-id-4052595.html 是不是觉得很玄?像思念一样玄?那好,我们来看点具体的,比如935行,INIT_DELA ...
- 如何将IOS版本的更新下载文件指向到自己的服务器
针对那些使用企业签名但是没有发布到AppSotre的IOS版本APP自动更新问题解决方案: 在apicloud中是这样说明的: 因为要填写plist地址所以不能向安卓那样直接填写服务器文件地址,但是直 ...
- [SDOI2009]HH去散步 「矩阵乘法计数」
计数问题也许可以转化为矩阵乘法形式 比如若该题没有不能在一条边上重复走的条件限制,那么直接将邻接矩阵转化为矩阵乘法即可 故 矩阵乘法计数 对于计数问题,若可以将 \(n\) 个点表示成 \(n \ti ...
- [原创]jQuery Validation范例
上班无事,学习jQuery Validation,于是手写一公共范例,并收藏以便后用 验证操作类formValidatorClass.js }); 测试页index.html * {} ...
- 在内部局域网内搭建HTTPs
在内部局域网内搭建HTTPs 配置环境 Windows版本:Windows Server 2008 R2 Standard Service Pack 1 系统类型: 64 位操作系统 内存 ...
- LeetCode(11):盛最多水的容器
Medium! 题目描述: 给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) .画 n 条垂直线,使得垂直线 i 的两个端点分别为 (i, ai) 和 (i, ...
- bnu 10809 聚餐
Lolilu大牛又要请客了~~有些同学呢,是果断要去的,而有些同学呢,只有确定心中的大牛会参加,他才会参加.Lolilu决定请大家去吃金钱豹,因此希望你告诉他一共会有多少人参加,他才知道带多少钱比较合 ...
- [转] CSSOM视图模式(CSSOM View Module)相关整理
以下就是一些API属性的相关内容,包括兼容性,使用,测试等. 一.Window视图属性 这些属性可以hold住整个浏览器窗体大小.微软则将这些API称为“Screenview 接口”.包括:inner ...
- MVC底层原理
窥探ASP.Net MVC底层原理 实现跨越Session的分布式TempData 1.问题的引出 我相信大家在项目中都使用过TempData,TempData是一个字典集合,一般用于两个请求之间临时 ...
- 【LOJ】#2073. 「JSOI2016」扭动的回文串
题解 就是一个回文串拼上左右两端 类似二分找lcp这么做 可以直接用哈希找回文串 注意要找A串前半部分,B串找后半部分 代码 #include <bits/stdc++.h> #defin ...