一、消息处理程序的概念

  信息处理程序(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. bzoj 3631 松鼠的新家 (树链剖分)

    链接: https://www.lydsy.com/JudgeOnline/problem.php?id=3631 思路: 直接用树链剖分求每一次运动,因为这道题只需要区间增添,单点求值,没必要用线段 ...

  2. JXOI 2018 简要题解

    目录 「JXOI2018」游戏 题意 题解 代码 「JXOI2018」守卫 题意 题解 代码 「JXOI2018」排序问题 题意 题解 代码 总结 「JXOI2018」游戏 题意 可怜公司有 \(n\ ...

  3. Ubuntu相关配置

    1.Ubuntu配置root密码 2.开机ssh连接--nat   编辑网络设置端口转发

  4. virtio,macvtap,sriov

    本文转自http://xiaoli110.blog.51cto.com/1724/1558984 一个完整的数据包从虚拟机到物理机的路径是: 虚拟机--QEMU虚拟网卡--虚拟化层--内核网桥--物理 ...

  5. Linux及Windows查看占用端口的进程

    想必大家在部署环境启动服务的时候,会遇到服务起不起来的问题,看日志,说是端口被占用了. 有的时候,我们不想改端口,那么,就需要去查看到底是哪个应用把这个端口给占用了,然后干掉它即可. 下面分别列举li ...

  6. [luogu1486][郁闷的出纳员]

    题目链接 思路 这个题其实就是对于treap中的删除操作进行一些修改.自己yy了一种做法.就是在删除的时候,如果要删除的数比这棵子树的根大,那么就把根变成根的右孩子,这样就相当于删除了整棵左子树和根节 ...

  7. 利用captcha库绘制验证码

    #导包 from captcha.image import ImageCaptcha from PIL import Image import random import time import os ...

  8. linux系统调用之系统控制

    ioctl I/O总控制函数 _sysctl 读/写系统参数 acct 启用或禁止进程记账 getrlimit 获取系统资源上限 setrlimit 设置系统资源上限 getrusage 获取系统资源 ...

  9. Day3--Python--字符串,for循环,迭代

    常见的基本数据类型: 1.int 整数 主要用来进行数学运算 2.bool 布尔. 判断真假. if 和 while循环中常用 3.str 字符串,一般放小量数据 4.list 列表.可以存放大量的数 ...

  10. POJ 2112 Optimal Milking (Dinic + Floyd + 二分)

    Optimal Milking Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 19456   Accepted: 6947 ...