一、消息处理程序的概念

  信息处理程序(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)的更多相关文章

  1. 【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 ...

  2. 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 重点: 实现多级子目录的压缩, ...

  3. ASP.NET Web API中的Controller

    虽然通过Visual Studio向导在ASP.NET Web API项目中创建的 Controller类型默认派生与抽象类型ApiController,但是ASP.NET Web API框架本身只要 ...

  4. 【ASP.NET Web API教程】6.2 ASP.NET Web API中的JSON和XML序列化

    谨以此文感谢关注此系列文章的园友!前段时间本以为此系列文章已没多少人关注,而不打算继续下去了.因为文章贴出来之后,看的人似乎不多,也很少有人对这些文章发表评论,而且几乎无人给予“推荐”.但前几天有人询 ...

  5. 【ASP.NET Web API教程】4.3 ASP.NET Web API中的异常处理

    原文:[ASP.NET Web API教程]4.3 ASP.NET Web API中的异常处理 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本系列教程,请先看前面的内 ...

  6. 目标HttpController在ASP.NET Web API中是如何被激活的:目标HttpController的创建

    目标HttpController在ASP.NET Web API中是如何被激活的:目标HttpController的创建 通过上面的介绍我们知道利用HttpControllerSelector可以根据 ...

  7. Web APi 2.0优点和特点?在Web APi中如何启动Session状态?

    前言 曾几何时,微软基于Web服务技术给出最流行的基于XML且以扩展名为.asmx结尾的Web Service,此服务在.NET Framework中风靡一时同时也被.NET业界同仁所青睐,几年后在此 ...

  8. WEB API 中HTTP的get、post、put,delete 请求方式

    一.WEB API 中HTTP 请求方式的四个主要方法 (GET, PUT, POST, DELETE), 按照下列方式映射为 CURD 操作: 1.POST 用于新建资源,服务端在指定的URI 上创 ...

  9. 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【五】——在Web Api中实现Http方法(Put,Post,Delete)

    系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 在Web Api中,我们对资源的CRUD操作都是通过相应的Http方法来实现——Post(新 ...

随机推荐

  1. POJ 3580-SuperMemo-splay树

    很完整的splay操作.做了这题就可以当板子用了. #include <cstdio> #include <algorithm> #include <cstring> ...

  2. Educational Codeforces Round 33 (Rated for Div. 2) F. Subtree Minimum Query(主席树合并)

    题意 给定一棵 \(n\) 个点的带点权树,以 \(1\) 为根, \(m\) 次询问,每次询问给出两个值 \(p, k\) ,求以下值: \(p\) 的子树中距离 \(p \le k\) 的所有点权 ...

  3. 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 ...

  4. python中lambda的使用

    为什么我们需要lambda? 既然有了def可以用来定义函数,我们为什么还需要lambda来定义.根据我的使用情况我认为lambda的优点在于: 非常适合用来构造只使用一次的函数,可以是匿名函数 有利 ...

  5. 【BZOJ2870】最长道路(边分治)

    [BZOJ2870]最长道路(边分治) 题面 BZOJ权限题 Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样 ...

  6. rt-thread 学习路线

    @2019-01-25 [小记] > BSP制作与使用 将板载资源.芯片外设全部制作BSP,做到使用时只需在 menuconfig 中配置即用

  7. Apache rewrite地址重写

    Apache-rewrite+13个经典案例Apache 重写规则的常见应用(rewrite)一:目的 如何用Apache重写规则来解决一些常见的URL重写方法的问题,通过常见的 实例给用户一些使用重 ...

  8. Equivalent Sets HDU - 3836 (Tarjan)

    题目说给出一些子集,如果A是B的子集,B是A的子集,那么A和B就是相等的,然后给出n个集合m个关系,m个关系表示u是v的子集,问你最小再添加多少个关系可以让这n个集合都是相等的 如果这n个几个都是互相 ...

  9. 【lua】lua安装学习

    Lua 是用标准C语言编写并以源代码形式开放的一种轻量小巧的脚本语言,设计目的是为了嵌入应用程序中,为应用程序提供灵活的扩展和定制功能. lua官网 http://www.lua.org/ 安装lua ...

  10. DNA Consensus String

    题目(中英对照): DNA (Deoxyribonucleic Acid) is the molecule which contains the genetic instructions. It co ...