Web API中的消息处理程序(Message Handler)
一、消息处理程序的概念
信息处理程序(Message Handler)接收HTTP请求并返回一个HTTP响应的类。Message Handler继承 HttpMessageHandler 类。
通常,一系列消息处理程序协同工作。第一个Message Handler接收HTTP请求,进行一些处理,并将请求提供给下一个Message Handler。在某些时候,响应被创建并返回到Message Handler,此模式称为委托处理程序(delegating handler)。
二、服务器端消息处理程序
在服务器端,Web API管道使用一些内置的消息处理程序:
HttpServer 从主机获取请求。
HttpRoutingDispatcher 根据请求进行路由。
HttpControllerDispatcher 将请求发送到Web API控制器。
我们可以向管道添加自定义处理程序。消息处理程序更适合处理Http messages(比起控制器)。因为Message Handler可以:
读取或修改请求标头。
为响应添加响应标头。
在请求到达控制器之前验证请求。
此图显示了插入管道的两个自定义处理程序:

三、自定义Message Handler
第一步:创建Message Handler
要编写自定义消息处理程序,请从 System.Net.Http.DelegatingHandler 派生并覆盖 SendAsync 方法。此方法具有以下签名:
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
该方法将HttpRequestMessage作为输入,并异步返回HttpResponseMessage。典型的实现执行以下操作:
.处理请求消息。
.调用base.SendAsync将请求发送到内部处理程序。
.内部处理程序返回响应消息。(此步骤是异步的。)
.处理响应并将其返回给调用者。
一个简单的栗子:
public class MessageHandler1 : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
Debug.WriteLine("Process request");
// Call the inner handler.
var response = await base.SendAsync(request, cancellationToken);
Debug.WriteLine("Process response");
return response;
}
}
调用 base.SendAsync 是异步的。如果处理程序在此调用后执行任何操作,请使用await关键字。
委托处理程序也可以跳过inner handler
一个跳过inner handler的栗子:
public class MessageHandler2 : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
// Create the response.
var response = new HttpResponseMessage(HttpStatusCode.OK){
Content = new StringContent("Hello!")}; // Note: TaskCompletionSource创建一个不包含委托的task
var tsc = new TaskCompletionSource<HttpResponseMessage>();
tsc.SetResult(response); // Also sets the task state to "RanToCompletion"
return tsc.Task;
}
}
如果delegate handler在创建响应时不调用base.SendAsync,则请求将跳过管道的其余部分。这对于验证请求的处理程序(创建错误响应)非常有用。
第二步:将处理程序添加到管道
要在服务器端添加消息处理程序,请将处理程序添加到 HttpConfiguration.MessageHandlers 集合中。
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MessageHandlers.Add(new MessageHandler1());
config.MessageHandlers.Add(new MessageHandler2());
// Other code not shown...
}
}
消息处理程序的调用顺序与它们在MessageHandlers集合中的显示顺序相同。因为它们是嵌套的,所以响应消息反向传播。
四、自定义消息处理程序实例
4.1 添加自定义响应标头
这是一个Message Handler,它为每个响应消息添加一个自定义标头:
public class CustomHeaderHandler : DelegatingHandler
{
async protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
response.Headers.Add("X-Custom-Header", "This is my custom header.");
return response;
}
}
首先,处理程序调用base.SendAsync将请求传递给inner handler。inner handler返回响应消息,但它使用Task <T>对象异步执行,在base.SendAsync异步完成之前,响应消息不可用。
4.2 检查API密钥
某些Web服务要求客户在其请求中包含API密钥。以下示例显示了消息处理程序如何检查有效API密钥的请求:
public class ApiKeyHandler : DelegatingHandler
{
public string Key { get; set; }
public ApiKeyHandler(string key)
{
this.Key = key;
}
//重写sendAsyc
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (!ValidateKey(request))
{
//没有通过则创建response,code为403
var response = new HttpResponseMessage(HttpStatusCode.Forbidden);
var tsc = new TaskCompletionSource<HttpResponseMessage>();
tsc.SetResult(response);
return tsc.Task;
}
return base.SendAsync(request, cancellationToken);
}
//验证密钥
private bool ValidateKey(HttpRequestMessage message)
{
var query = message.RequestUri.ParseQueryString();
string key = query["key"];
return (key == Key);
}
}
Message Handler在URI查询字符串中查找API密钥。如果查询字符串包含Key,则Message handler将请求传递给innner handler,没有key的话返回403。
4.3 Per-Route Message Handler
HttpConfiguration.MessageHandlers集合中的处理程序全局应用,有时候我们的Message Handler只针对特定的路径,如url中含有“admin”的,需要登陆后才能访问:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
//默认路由
config.Routes.MapHttpRoute(
name: "Route1",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//路由中指定Message Handler
config.Routes.MapHttpRoute(
name: "Route2",
routeTemplate: "api2/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
handler: new MessageHandler2() // per-route message handler
);
//全局的Message Handler
config.MessageHandlers.Add(new MessageHandler1()); // global message handler
}
}
在此示例中,如果请求URI与“Route2”匹配,则将分派请求MessageHandler2,如下图所示:

这时MessageHandler2替换默认的HttpControllerDispatcher。这个栗子中MessageHandler2创建响应,匹配“Route2”的请求永远不会转到控制器。这使我们可以使用自己的自定义响应替换整个Web API控制器机制。
我们也可以把路由的MessageHandler委托给 HttpControllerDispatcher ,通过HttpControllerDispatcher调度到控制器。
以下代码显示了如何配置此路由:
// delegating handlers.
DelegatingHandler[] handlers = new DelegatingHandler[] {
new MessageHandler3()
}; // Create a message handler chain with an end-point.
var routeHandlers = HttpClientFactory.CreatePipeline(
new HttpControllerDispatcher(config), handlers); config.Routes.MapHttpRoute(
name: "Route2",
routeTemplate: "api2/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: null,
handler: routeHandlers
);

这里总结了Web API中的Message Handler中的概念和基本用法,了解更多用法可以查看官网。
Web API中的消息处理程序(Message Handler)的更多相关文章
- 【ASP.NET Web API教程】5.5 ASP.NET Web API中的HTTP Cookie
原文:[ASP.NET Web API教程]5.5 ASP.NET Web API中的HTTP Cookie 5.5 HTTP Cookies in ASP.NET Web API 5.5 ASP.N ...
- C#实现多级子目录Zip压缩解压实例 NET4.6下的UTC时间转换 [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了 asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程 asp.net core异步进行新增操作并且需要判断某些字段是否重复的三种解决方案 .NET Core开发日志
C#实现多级子目录Zip压缩解压实例 参考 https://blog.csdn.net/lki_suidongdong/article/details/20942977 重点: 实现多级子目录的压缩, ...
- ASP.NET Web API中的Controller
虽然通过Visual Studio向导在ASP.NET Web API项目中创建的 Controller类型默认派生与抽象类型ApiController,但是ASP.NET Web API框架本身只要 ...
- 【ASP.NET Web API教程】6.2 ASP.NET Web API中的JSON和XML序列化
谨以此文感谢关注此系列文章的园友!前段时间本以为此系列文章已没多少人关注,而不打算继续下去了.因为文章贴出来之后,看的人似乎不多,也很少有人对这些文章发表评论,而且几乎无人给予“推荐”.但前几天有人询 ...
- 【ASP.NET Web API教程】4.3 ASP.NET Web API中的异常处理
原文:[ASP.NET Web API教程]4.3 ASP.NET Web API中的异常处理 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本系列教程,请先看前面的内 ...
- 目标HttpController在ASP.NET Web API中是如何被激活的:目标HttpController的创建
目标HttpController在ASP.NET Web API中是如何被激活的:目标HttpController的创建 通过上面的介绍我们知道利用HttpControllerSelector可以根据 ...
- Web APi 2.0优点和特点?在Web APi中如何启动Session状态?
前言 曾几何时,微软基于Web服务技术给出最流行的基于XML且以扩展名为.asmx结尾的Web Service,此服务在.NET Framework中风靡一时同时也被.NET业界同仁所青睐,几年后在此 ...
- WEB API 中HTTP的get、post、put,delete 请求方式
一.WEB API 中HTTP 请求方式的四个主要方法 (GET, PUT, POST, DELETE), 按照下列方式映射为 CURD 操作: 1.POST 用于新建资源,服务端在指定的URI 上创 ...
- 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【五】——在Web Api中实现Http方法(Put,Post,Delete)
系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 在Web Api中,我们对资源的CRUD操作都是通过相应的Http方法来实现——Post(新 ...
随机推荐
- POJ 3580-SuperMemo-splay树
很完整的splay操作.做了这题就可以当板子用了. #include <cstdio> #include <algorithm> #include <cstring> ...
- Educational Codeforces Round 33 (Rated for Div. 2) F. Subtree Minimum Query(主席树合并)
题意 给定一棵 \(n\) 个点的带点权树,以 \(1\) 为根, \(m\) 次询问,每次询问给出两个值 \(p, k\) ,求以下值: \(p\) 的子树中距离 \(p \le k\) 的所有点权 ...
- Hdoj 1086.You can Solve a Geometry Problem too 题解
Problem Description Many geometry(几何)problems were designed in the ACM/ICPC. And now, I also prepare ...
- python中lambda的使用
为什么我们需要lambda? 既然有了def可以用来定义函数,我们为什么还需要lambda来定义.根据我的使用情况我认为lambda的优点在于: 非常适合用来构造只使用一次的函数,可以是匿名函数 有利 ...
- 【BZOJ2870】最长道路(边分治)
[BZOJ2870]最长道路(边分治) 题面 BZOJ权限题 Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样 ...
- rt-thread 学习路线
@2019-01-25 [小记] > BSP制作与使用 将板载资源.芯片外设全部制作BSP,做到使用时只需在 menuconfig 中配置即用
- Apache rewrite地址重写
Apache-rewrite+13个经典案例Apache 重写规则的常见应用(rewrite)一:目的 如何用Apache重写规则来解决一些常见的URL重写方法的问题,通过常见的 实例给用户一些使用重 ...
- Equivalent Sets HDU - 3836 (Tarjan)
题目说给出一些子集,如果A是B的子集,B是A的子集,那么A和B就是相等的,然后给出n个集合m个关系,m个关系表示u是v的子集,问你最小再添加多少个关系可以让这n个集合都是相等的 如果这n个几个都是互相 ...
- 【lua】lua安装学习
Lua 是用标准C语言编写并以源代码形式开放的一种轻量小巧的脚本语言,设计目的是为了嵌入应用程序中,为应用程序提供灵活的扩展和定制功能. lua官网 http://www.lua.org/ 安装lua ...
- DNA Consensus String
题目(中英对照): DNA (Deoxyribonucleic Acid) is the molecule which contains the genetic instructions. It co ...