1. Http Message Handler

WebApi中的MessageHandler类似MVC中的filter,可用于请求/响应到达真正目标前对请求或者响应进行修改,比如:用户身份验证,请求头修改,返回数据的修改等。

先看一张webapi的请求流程图:

{Request}                          }  Pipeline 流向从上到下

|= HttpServer

|= { DelegatingHandler }       - 这里是个集合,可能存在0-n 个messagehandler

|= Inner Message Handler       - 内置的一些消息处理

|= HttpRoutingDispatcher

|= HttpControllerDispatcher

|= Controller

| Action

{ Response }                 }  end

从上面webapi:Http message lifecyle简图我们可以看出,在存在DelegatingHandler情况下,任何请求/响应在到达真正的目标前,都要先被DelegatingHandler处理,也就意味着DelegatingHandler拥有了决定继续响应请求和修改返回响应结果的权利.这里的delegatingHandler就是我们的messagehandler。

如果你了解nodejs express框架,你会发现messagehandler跟express框架的中间件在概念上基本是一样的。

通过自定义MessageHandler我们可以做很多针对请求/响应定制性的东西.

2. 自定义Message handler

自定义Messsage handler有两种途径,一种是直接通过继承HttpMessageHandler实现抽象方法SendAsync,另一种是通过继承DelegatingHandler重载SendAysnc方法实现.

(DelegatingHandler本身就是派生与HttpMesssageHandler,实现了SendAsync抽象方法,DelegatingHandlerh和HttpMessageHandler都是abstract类)

public abstract DelegatingHandler: HttpMessageHandler{  //HttpMessageHandler{ [abstrct][method] sendAsync() }
//some some //sendasync
protected Task<HttpResponseMessage> SendAsync(....){
//some
//一些内置的操作
return this.innerHandler.SendAsync(...);
} //innermessagehandle
private HttpMessageHandler innerHandler ;
}

实现了自定义的message handler,同时还需要添加到管线中消息处理器才能起作用,此时的消息处理器是全局的会被应用到所有的请求/响应上,

注册消息处理器可以通过HttpConfiguration::MessageHandlers.Add( 自定义消息处理器 ) .

a.一个简单的消息处理器. 实现了两个操作:

1) 如果请求消息头中没有包含X-TOKEN标识,那么直接返回NotFound,终止消息的继续传递

2) 针对响应消息,在响应消息头添加标识X-CUSTOM-HEADER

public class CustomTokenValidMessageHandler: DelegatingHandler
{
private readonly string X-TOKEN = "X-TOKEN";
//override sendAsync
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request , CancellationToken token )
{
//判断请求头中是否存在X-TOKEN标识以及值
//不存在情况下直接返回notfound,终止请求继续向下传递
if( !request.Headers.Contains(X-TOKEN) ){
var res = new HttpResponseMessage(HttpStatusCode.NotFound);
//这里使用TaskCompletionSource,可以通过setresult手动设置结果
var ts = new TaskCompletionSource<HttpResponseMessage>()
ts.SetResult( res ); return ts.Task;
} //2:t通过修改响应头,添加一个标识X-CUSTOM-HEADER
var response = base.SendAsync(request,token);
response.Result.Headers.Add("X-CUSTOM-HEADER","VIsonme-19-fz");
return response;
}
} //注册Message handler

b. MS官方的一个很好API验证的例子,在现实场景中都是常见的,比如某应用调用第三方WEB API,API方平台都会要求应用拥有一个key或者token.

public class APIKeyValidMessageHandler: DelegatingHandler

{
private string _app_api_key = string.Empty;
public APIKeyValidMessageHandler(string apikey){_app_api_key = apikey;}
private bool CheckApiKey( HttpRequestMessage req )
{
//解析查询字符串
var query_string = req.RequestUri.ParseQueryString();
var k = query_string["key"]; return (k == this._app_api_key);
} protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request , CancellationToken token )
{
if( !this.CheckApiKey( request ))
{
//key无效情况
var res = new HttpResponseMessage(HttpStatusCode.Forbidden);
var ts = new TaskCompletionSource<HttpResponseMessage>()
ts.SetResult( res ); return ts.Task;
} return base.SendAsync(request , token);
}
} //注册message handler

3.给指定的路由添加Message handler.

上面方式注册的消息处理器都是全局的,针对所有请求/响应,在某些场景下我们可能并不想消息处理器全局应用而是只针对某些路由,比如:某些API的访问我只希望一些核心的action需要被验证而其他的接口可以被大众化访问,这个时候就没有必要将身份验证的消息处理器应用到全局了 .

针对某些路由注册Message Handler,可以在HttpConfiguration::Routes::MapHttpRoute中给handler字段指定仅仅在该route上被处理的Message handler.

==> WebApiConfig.cs ==> Register [method]

config.Routes.MapHttpRoute(
name:"route name",
routeTemplate:"api/{controller}/{action}/{id},
default: new{id=RouteParameter.Optional},
constraints:null,
handler: new APIKeyValidMessageHandler("V-198-fz")
); //上面我们指定了handler为APIKeyValidMessageHandler
//那么APIKeyValidMessageHandler仅仅作用在该路由上,而不会
//被应用到全局
//如果希望全局应用只要在config.MessageHandlers.Add(your mh)
//就可以了

这个时候Http message lifecyle简图就变成了:

{ Request }

| = HttpServer

| = Message Handler

| = RouteDispathcer

| ----- 》----------------------{route 1 } ------------

|= Defaut route                  |

|-- Controller dispatcher        |= custom messge handler

|--------------------------------|------------------> { Response }

通过上面我们将messagehandler应用到指定的路由但是从简图我们看出,这个时候我们在route1看不到controller dispathcer了,controller diapathcer被我们自定义的message handler给取代了。

这种情况请不是我们所期望的,我们期望应该是将message hander插入到指定的route中,但是并不应该影响到我们原先route中应该的逻辑,也就是正确的应该是

route1 : 流程应该是这样的

{ custom message handler }

| Controller distatcher

| controller

{ response }

我们需要重新配置我们的message handler,通过HttpClientFactory创建一个路由管道点

DelegatingHandler[] handlers = new DelegatingHandler[]{
new APIKeyValidMessageHandler()
}; var routeHandlers = HttpClientFactory.CreatePipeline( new HttpControllerDispatcher(config),handler); //MAP HTTP ROUTE
config.Routes.MapHttpRoute(
name:"route1",
routeTemplate:"api/{controller}/{id}",
defaults: ///
constraints: null,
handlers:routeHandlers
);

AspNet WebApi : MessageHandler(消息处理器 )的更多相关文章

  1. Asp.Net Web API 2第四课——HttpClient消息处理器

    Asp.Net Web API 导航   Asp.Net Web API第一课:入门http://www.cnblogs.com/aehyok/p/3432158.html Asp.Net Web A ...

  2. WebAPI 消息处理器

    由上图可以看出消息处理器的使用场合和使用方法. 使用场合: HttpServer 得到请求时. public static class WebApiConfig { public static voi ...

  3. 【ASP.NET Web API教程】5.1 HTTP消息处理器

    原文:[ASP.NET Web API教程]5.1 HTTP消息处理器 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本系列教程,请先看前面的内容. 5.1 HTTP ...

  4. 【ASP.NET Web API教程】3.4 HttpClient消息处理器

    原文:[ASP.NET Web API教程]3.4 HttpClient消息处理器 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容. 3.4 ...

  5. vs2012安装Microsoft.AspNet.WebApi.WebHost

    工具---库程序包管理器---程序包管理器控制台:输入下面命令:  Install-Package Microsoft.AspNet.WebApi.WebHost 

  6. AspNet WebApi OData 学习

    OData介绍:是一个查询和更新数据的Web协议.OData应用了web技术如HTTP.Atom发布协议(AtomPub)和JSON等来提供对不同应用程序,服务 和存储的信息访问.除了提供一些基本的操 ...

  7. Asp.Net WebApi+Microsoft.AspNet.WebApi.Core 启用CORS跨域访问

    WebApi中启用CORS跨域访问 1.安装 Nugget包Microsoft.AspNet.WebApi.Cors This package contains the components to e ...

  8. AspNet.WebAPI.OData.ODataPQ

    AspNet.WebAPI.OData.ODataPQ实现WebAPI的分页查询服务 AspNet.WebAPI.OData.ODataPQ实现WebAPI的分页查询服务-(个人拙笔) AspNet. ...

  9. AspNet.WebAPI.OData.ODataPQ实现WebAPI的分页查询服务-(个人拙笔)

    AspNet.WebAPI.OData.ODataPQ 这是针对 Asp.net WebAPI OData 协议下,查询分页.或者是说 本人在使用Asp.Net webAPI 做服务接口时写的一个分页 ...

随机推荐

  1. HTML Meta, http-equiv, Refresh

    原文: http://www.lifelaf.com/blog/?p=481 在HTML页面中,如果想实现定时刷新或重定向,我们可以使用meta标签的refresh功能: <!-- 5秒后刷新页 ...

  2. Django中的CSRF

    CSRF(Cross Site Request Forgery, 跨站域请求伪造) CSRF 背景与介绍 CSRF(Cross Site Request Forgery, 跨站域请求伪造)是一种网络的 ...

  3. bzoj4448 SCOI2015 情报传递 message

    传送门bzoj4448 题解 离线之后构建树上主席树,每个点的线段树维护到根路径的信息,不用链剖(我的链剖只是拿来求\(\mathrm{lca}\)的),时空复杂度\(O(n\log{n})\). c ...

  4. Pencil-一个开源免费的UI原型工具,自带ios和android模板

    Pencil是一个开源免费的UI原型工具,自带ios和android模板,可以很方便的做mockup. 下图是一个官方展示的模板:         

  5. 【原创】javascript——事件思维导图

  6. AFNetworking 使用总结

    NSString *URLTmp = @""; NSString *URLTmp1 = [URLTmp stringByAddingPercentEscapesUsingEncod ...

  7. android异步任务载入数据界面实现

    android 异步任务的一个后台方法本质是开启一个线程完毕耗时操作,其它onPostExecute方法和onPreExecute方法执行在UI主线程用于更新UI界面.为了提高用户体验常见的异步任务载 ...

  8. 关于verilog中if与case语句不完整产生锁存器的问题 分类: FPGA 2014-11-08 17:39 260人阅读 评论(0) 收藏

    在很多地方都能看到,verilog中if与case语句必须完整,即if要加上else,case后要加上default语句,以防止锁存器的发生,接下来就来说说其中原因. 一,什么是锁存器?锁存器与触发器 ...

  9. 一、Bitmap的recycle问题

    尽管Android有自己的垃圾回收机制,对于是不是要我们自己调用recycle,还的看情况而定.假设仅仅是使用少量的几张图片,回收与否关系不大.但是若有大量bitmap须要垃圾回收处理,那必定垃圾回收 ...

  10. 晨曦之光 linux Crontab 使用(转)

    cron用法说明 cron的用法老是记不住,索性写下来备忘.下文内容大部分是根据<Cron Help Guide>翻译而来,有些部分是自己加上的. 全文如下: cron来源于希腊单词chr ...