WebApi2官网学习记录--HTTP Message Handlers
Message Handlers是一个接收HTTP Request返回HTTP Response的类,继承自HttpMessageHandler
通常,一些列的message handler被链接到一起。第一个handler收到http request做一些处理,然后将request传递到下一个handler。在某时刻,response被创并返回。这种模式被称为delegating hanlder
服务端消息处理
在服务端,WebAPI管道使用一些内建的message handlers
HttpServer
从主机获取requestHttpRoutingDispacher
基于路由分配requestHttpControllerDispacher
发送request到WebAPI的controller
可以在pipline中自定义message handlers,如图,展示了两个自定义的handler
自定义 Message Handlers
自定义message handler需要实现System.Net.Http.DelegatingHandler
接口,并重载SendAsync
方法。
Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken);
典型的实现通过一些流程:
- 处理request message
- 调用
base.SendAsync
将request传递到内部的handler(inner handler) - 内部的handler返回一个response message(这步是异步的)
- 处理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的例子
跳过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);
}
}
重写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的更多相关文章
- WebApi2官网学习记录--HttpClient Message Handlers
在客户端,HttpClient使用message handle处理request.默认的handler是HttpClientHandler,用来发送请求和获取response从服务端.可以在clien ...
- WebApi2官网学习记录--- Authentication与Authorization
Authentication(认证) WebAPI中的认证既可以使用HttpModel也可以使用HTTP message handler,具体使用哪个可以参考一下依据: 一个HttpModel可以 ...
- WebApi2官网学习记录---批量处理HTTP Message
原文:Batching Handler for ASP.NET Web API 自定义实现HttpMessageHandler public class BatchHandler : HttpMess ...
- WebApi2官网学习记录---Cookie
Cookie的几个参数: Domain.Path.Expires.Max-Age 如果Expires与Max-Age都存在,Max-Age优先级高,如果都没有设置cookie会在会话结束后删除cook ...
- WebApi2官网学习记录---Tracing
安装追踪用的包 Install-Package Microsoft.AspNet.WebApi.Tracing Update-Package Microsoft.AspNet.WebApi.WebHo ...
- WebApi2官网学习记录---异常处理
HttpResponseException 当WebAPI的控制器抛出一个未捕获的异常时,默认情况下,大多数异常被转为status code为500的http response即服务端错误. Http ...
- WebApi2官网学习记录---Html Form Data
HTML Forms概述 <form action="api/values" method="post"> 默认的method是GET,如果使用GE ...
- WebApi2官网学习记录---Configuring
Configuration Settings WebAPI中的configuration settings定义在HttpConfiguration中.有一下成员: DependencyResolver ...
- WebApi2官网学习记录---单元测试
如果没有对应的web api模板,首先使用nuget进行安装 例子1: ProductController 是以硬编码的方式使用StoreAppContext类的实例,可以使用依赖注入模式,在外部指定 ...
随机推荐
- .NET中使用GridView控件输入数据时出现“ Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index"的问题
在.NET中使用GridView控件的在线编辑数据时,出现了“ Index was out of range. Must be non-negative and less than the size ...
- ORACLE用户操作的一些常用操作总结【weber出品】
一.创建一个表空间 create tablespace pioneer_data datafile '/u01/datafile/pioneer_datadbf' size 100m autoexte ...
- eclipse使用和优化配置
一.简介 eclipse 可谓是Java开发界的神器,基本占据了大部分的Java开发市场,而且其官方还对其他语言提供支持,如C++,Ruby,JavaScript等等.为 什么使用它?我想离不开下面的 ...
- ubuntu 安装RPM软件包
red hat 系统用rpm格式的文件安装软件,ubuntu安装软件是用deb格式的文件安装 在ubuntu上安装rmp文件格式的软件包步骤: 1.安装转换软件 alien(需要联网) apt-get ...
- Slony-I双机备份
测试环境:postgresql 9.3.5,slony-I2.2.3(application stack builder提供)以下参考网上教程亲自测试总结 ---------------------- ...
- 标准程序员系列-Github篇-初始化一个代码仓库
下面将一步步介绍怎样使用GitHub来初始化一个项目的版本控制仓库: 1. 到GitHub上注册自己的账号:https://github.com/ 2. 创建第一个代码仓库一个仓库相当于一个项目的代码 ...
- iOS开发 自定义navigationleftItem 之后手势失效的问题
@property (nonatomic, strong) UIViewController *currentShowVC; //设置代理 self.navigationController.inte ...
- LeetCode_Restore IP Addresses
Given a string containing only digits, restore it by returning all possible valid IP address combina ...
- windows下使用批处理调用exe和服务
手动调用exe或者启动服务很麻烦,可以使用.bat批处理文件,双击运行即可.步骤如下:创建一个新的txt文件但是保存成.bat结尾的文件(选择用记事本打开编写命令),输入代码内容格式如下: @echo ...
- 桌面上嵌入窗口(桌面日历)原理探索(将该窗口的Owner设置成桌面的Shell 窗口,可使用SetWindowLong更改窗口的GWL_HWNDPARENT,还要使用SetWindowPos设置Z-Order)
今天在QQ群里有人问怎样实现将自己的窗口嵌入桌面,让它和桌面融为一体,就像很多桌面日历软件那样. 我当时想到的就是建立一个Child Window,将他的父窗口设置成桌面Shell窗口就可以了.但是 ...