Message Handlers是一个接收HTTP Request返回HTTP Response的类,继承自HttpMessageHandler

通常,一些列的message handler被链接到一起。第一个handler收到http request做一些处理,然后将request传递到下一个handler。在某时刻,response被创并返回。这种模式被称为delegating hanlder

服务端消息处理

在服务端,WebAPI管道使用一些内建的message handlers

  • HttpServer 从主机获取request
  • HttpRoutingDispacher 基于路由分配request
  • HttpControllerDispacher 发送request到WebAPI的controller

可以在pipline中自定义message handlers,如图,展示了两个自定义的handler

自定义 Message Handlers

自定义message handler需要实现System.Net.Http.DelegatingHandler接口,并重载SendAsync方法。

Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken);

典型的实现通过一些流程:

  1. 处理request message
  2. 调用base.SendAsync将request传递到内部的handler(inner handler)
  3. 内部的handler返回一个response message(这步是异步的)
  4. 处理response并返回给调用者

一个简单的例子:

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;
}
}

当然,也可以跳过inner handler,直接创建一个response(这种方式对于验证request很有用)

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 creates a task that does not contain a delegate.
var tsc = new TaskCompletionSource<HttpResponseMessage>();
tsc.SetResult(response); // Also sets the task state to "RanToCompletion"
return tsc.Task;
}
}

添加Handler到Pipeline

public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MessageHandlers.Add(new MessageHandler1());
config.MessageHandlers.Add(new MessageHandler2()); // Other code not shown...
}
}

Message Handler被调用的顺序与添加到MessageHandlers集合的顺序相同,由于是嵌套的response message消息传播的方向正好与此相反。

对于inner handlers我们不需要设置,WebAPI框架会自动连接。

Per-Route Message Handlers

既可以在 HttpConfiguration.MessageHandlers集合中设置Handlers应用到globally范围,也可以在指定路由上添加一个message handler

public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "Route1",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
); config.Routes.MapHttpRoute(
name: "Route2",
routeTemplate: "api2/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: null,
handler: new MessageHandler2()// per-route message handler
); config.MessageHandlers.Add(new MessageHandler1()); // global message handler
}
}

通过以上配置,如果URI匹配"Route2",请求将被分配到MessageHandler2。如下图所示:

注意:MessageHandler2会替代默认的HttpControllerDispatcher,匹配"Route2"的request将不能找到对应的controller,可以通过手动建立HttpControllerDispatcher来解决。

// List of 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
);

使用Message Handler的例子

  1. 跳过inner handler 直接返回response

    /// <summary>
    /// 跳过inner handler 直接返回response
    /// </summary>
    public class MyMessageHandler2: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 creates a task that does not contain a delegate.
    var tsc = new TaskCompletionSource<HttpResponseMessage>();
    tsc.SetResult(response); // Also sets the task state to "RanToCompletion"
    // return tsc.Task;
    return base.SendAsync(request,cancellationToken);
    }
    }
  2. 重写Request method

     /// <summary>
    /// 重写Request method
    /// </summary>
    public class MethodOverrideHandler:DelegatingHandler
    {
    readonly string[] _methods = { "DELETE", "HEAD", "PUT" };
    const string _header= "X-HTTP-Method-Override"; protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
    if (request.Method == HttpMethod.Post && request.Headers.Contains(_header))
    {
    var method = request.Headers.GetValues(_header).FirstOrDefault();
    if (_methods.Contains(method, StringComparer.InvariantCulture))
    {
    request.Method = new HttpMethod(method);
    }
    }
    return base.SendAsync(request, cancellationToken);
    }
    }

WebApi2官网学习记录--HTTP Message Handlers的更多相关文章

  1. WebApi2官网学习记录--HttpClient Message Handlers

    在客户端,HttpClient使用message handle处理request.默认的handler是HttpClientHandler,用来发送请求和获取response从服务端.可以在clien ...

  2. WebApi2官网学习记录--- Authentication与Authorization

    Authentication(认证)   WebAPI中的认证既可以使用HttpModel也可以使用HTTP message handler,具体使用哪个可以参考一下依据: 一个HttpModel可以 ...

  3. WebApi2官网学习记录---批量处理HTTP Message

    原文:Batching Handler for ASP.NET Web API 自定义实现HttpMessageHandler public class BatchHandler : HttpMess ...

  4. WebApi2官网学习记录---Cookie

    Cookie的几个参数: Domain.Path.Expires.Max-Age 如果Expires与Max-Age都存在,Max-Age优先级高,如果都没有设置cookie会在会话结束后删除cook ...

  5. WebApi2官网学习记录---Tracing

    安装追踪用的包 Install-Package Microsoft.AspNet.WebApi.Tracing Update-Package Microsoft.AspNet.WebApi.WebHo ...

  6. WebApi2官网学习记录---异常处理

    HttpResponseException 当WebAPI的控制器抛出一个未捕获的异常时,默认情况下,大多数异常被转为status code为500的http response即服务端错误. Http ...

  7. WebApi2官网学习记录---Html Form Data

    HTML Forms概述 <form action="api/values" method="post"> 默认的method是GET,如果使用GE ...

  8. WebApi2官网学习记录---Configuring

    Configuration Settings WebAPI中的configuration settings定义在HttpConfiguration中.有一下成员: DependencyResolver ...

  9. WebApi2官网学习记录---单元测试

    如果没有对应的web api模板,首先使用nuget进行安装 例子1: ProductController 是以硬编码的方式使用StoreAppContext类的实例,可以使用依赖注入模式,在外部指定 ...

随机推荐

  1. 关于Discuz!nt论坛编辑器图片上传bug,flash域的问题

    正在整discuz!nt,现在没有什么人弄了把? 上个星期突然来了个bug,搞死我了,论坛图片不能上传,上传卡在100%没反应了,于是我发现ajax发送到AttachUpload.cs时queryst ...

  2. Code First研究学习2_基本的错误及解决方法

    使用Code First时总有很多的问题出现,以下列举了一些基本的错误及解决方法! 1.当用Enable-Migrations启动数据库迁移后,如果再继续输入Enable-Migrations命令,则 ...

  3. acm poj1260 dp

    题目大意: 买珍珠,每买一种珍珠需要额外付出十个这种珍珠的钱,但你可以买比这种珍珠高品质的珍珠来替换它(那么就只需要那高品质付出那额外的十个珍珠的钱了,但是每个珍珠的价钱也变化了) 这是一个dp. 令 ...

  4. QML学习心得

    Qt Quick之于QML,正如Qt 之于 C++,QML是Qt中开发的一个新的语言,而Qt Quick是这个语言的一个组件库,其中包含了很多用QML写的可以现成使用的组件. QML Hello Wo ...

  5. php 文件操作中几种方法整理

    1.获取文件夹下所有文件个数 echo ShuLiang("../0503lianxi"); function ShuLiang($filename) { if(is_dir($f ...

  6. DataTables列过滤器

    var table = $('#example').DataTable(); table.columns().flatten().each( function ( colIdx ) { // Crea ...

  7. Dr.Watson使用技巧摘要

    Dr.Watson使用技巧摘要 For Win98/WinME the executable is DRWATSON.EXEFor WinNT/Win2000/WinXP the executable ...

  8. STL string常用操作指令

    s.insert(pos,args); 在pos之前插入args指定的字符.pos可以是一个下标或一个迭代器.接受下标的版本返回一个指向s的引用;接受迭代器的版本返回指向第一个插入字符的迭代器. s. ...

  9. 页面正在载入js

    页面显示(pageshow)和页面隐藏(pagehide)事件 http://blog.163.com/jiang_tao_2010/blog/static/121126890200911403336 ...

  10. 利用好CSS,实现Qt控件美化

    一.CSS概念 级联样式表 (CSS) 包含应用于网页中的元素的样式规则.CSS 样式定义元素的显示方式以及元素在页中的放置位置.可以创建一个通用规则,只要 Web 浏览器遇到一个元素实例,或遇到一个 ...