博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ASP.NET Web API实践系列05,消息处理管道
阅读量:5032 次
发布时间:2019-06-12

本文共 4886 字,大约阅读时间需要 16 分钟。

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
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
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
SendAsync(HttpRequestMessage request, CancellationToken cacellationToken);
 
//别忘了,HttpServer的父类DelegatingHandler还有一个InnerHandler属性。
}
 
 

 

这里的HttpServer当然是可以实例化的,每一次实例化意味着创建了HttpMessageHandler类型的链条的头,就是HttpServer本身,也创建了链条的尾,就是Dispatcher属性所表示的HttpMessageHandler类型。

 

HttpConfiguration又是什么呢?

 
public class HttpConfiguration : IDisposable
{
...
public Collection
MessageHandlers{
get;}
}

 

原来,我们可以从HttpConfiguration的MessageHandlers属性中获取所有的HttpMessageHandler类型,当然也可以把自定义的HttpMessageHandler类型注册到这个MessageHandlers集合中去。

 

到这,已经蠢蠢欲动,跃跃欲试了,自定义DelegatingHandler可以登场了!大致是:

HttpServer自定义DelegatingHandlerHttpControllerDispatcher

 

举例:重新设置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模版,就如""中一样。

 

自定义一个派生于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
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)
{
//注册自定义的DelegatingHandler
config.MessageHandlers.Add(new MethodOverrideHandler());
 
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
 
// 取消注释下面的代码行可对具有 IQueryable 或 IQueryable
返回类型的操作启用查询支持。
// 若要避免处理意外查询或恶意查询,请使用 QueryableAttribute 上的验证设置来验证传入查询。
// 有关详细信息,请访问 http://go.microsoft.com/fwlink/?LinkId=279712。
//config.EnableQuerySupport();
 
// 若要在应用程序中禁用跟踪,请注释掉或删除以下代码行
// 有关详细信息,请参阅: http://www.asp.net/web-api
config.EnableSystemDiagnosticsTracing();
}
}
}
 
 

 

在ValuesController中public void Put(int id, [FromBody]string value)的方法体内打上断点。打开Fiddler,输入如下:

 

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

 

转载于:https://www.cnblogs.com/darrenji/p/4056159.html

你可能感兴趣的文章
出现函数重载错误call of overloaded ‘printfSth(double)’ is ambiguous
查看>>
SDUT 1941-Friday the Thirteenth(水)
查看>>
java API连接虚拟机上的hbase
查看>>
c#扩展出MapReduce方法
查看>>
Cookie工具类 - CookieUtil.java
查看>>
[转载]linux下各文件夹的结构说明及用途介绍
查看>>
HDUOJ----4502吉哥系列故事——临时工计划
查看>>
form action中get \post传递参数的问题
查看>>
CloudStack4.4安装 ubuntu14.04
查看>>
java.io.tmpdir在哪里?
查看>>
php session_unset与session_destroy的区别
查看>>
最近学习任务和安排
查看>>
每日一句(2014-9-17)
查看>>
初学Hadoop之单机模式环境搭建
查看>>
[Ubuntu] 关于使用 root 账号登录
查看>>
不要做沙和尚
查看>>
二维数组指针作为函数参数传递
查看>>
Mobile里实现Linear Rendering
查看>>
[PKU1679 The Unique MST]
查看>>
JavaScript 变量提升
查看>>