一、消息处理程序的概念

  信息处理程序(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. SQL 对等发布

    发布类型: 快照发布:发布服务器按预定的时间间隔向订阅服务器发送已发布数据的快照.事务发布:在订阅服务器收到已发布数据的初始快照后,发布服务器将事务流式传输到订阅服务器.对等发布:对等发布支持多主复制 ...

  2. 查询SQL执行情况

    /* 查询SQL执行情况 包含逻辑读取信息,执行信息等情况*/ SELECT creation_time N'语句编译时间' ,last_execution_time N'上次执行时间' ,total ...

  3. centos部署nextcloud

    简介 Nextcloud是一套用于创建和使用文件托管服务的客户端-服务器软件.它在功能上类似于Dropbox,虽然Nextcloud是免费的和开源的,允许任何人在私人服务器上安装和操作它.与Dropb ...

  4. Flask 构建微电影视频网站(一)

    Flask构建电影视频网站 Python MTV模型 Flask微内核 Flask扩展插件配置及使用方法 根据业务开发网站前后台功能 Flask结合MySQL数据库 你将可以独立开发网站 独立部署运维 ...

  5. Codeforces Bubble Cup 11 J. Moonwalk challenge加强版

    题意 有一棵 \(n\) 个节点的树,每条边上有一个字符,有 \(m\) 次询问. 每次会选定两个点 \(u, v\) , \(u\) 到 \(v\) 的路径上的字符形成了一个字符串 \(T\) ,再 ...

  6. python实用脚本集

    iScript 是Github上 PeterDing 大神写的一个脚本集,由多数的 python 脚本和少数GM脚本组成. 含有以下几个脚本: xiami.py - 下载或播放高品质虾米音乐(xiam ...

  7. kvm虚拟化管理

    虚拟化 KVM (kernel-based virtual machine) 常见的一些虚拟化的软件xen kvm vmware esx openVZ Oracle VM VirtualBox vsp ...

  8. 课后选做题:MyCP

    目录 CP命令了解 MyCP实现 CP命令了解 作用:cp指令用于复制文件或目录,如同时指定两个以上的文件或目录,且最后的目的地是一个已经存在的目录,则它会把前面指定的所有文件或目录复制到此目录中.若 ...

  9. Navicat Premium 12 破解(MySQL、MariaDB、MongoDB、SQL Server、SQLite)

    打开注入到安装目录中的exe中 破解提示(还没好,继续看下去) 如果你安装的是中文版,选一下中文版(英文默认即可),获取一下key(名字和组织可以自定义) 打开Navicat,选择注册(第一次打开选注 ...

  10. 我眼中的 Docker(二)Image

    Docker 安装 如何安装 docker 详见官网: installation 或者 中文指南. 不过 linux 上我推荐用 curl 安装,因为 apt-get 中源要么没有 docker,要么 ...