Message Handlers是一個接收HTTP Request返回HTTP Response的類,繼承自HttpMessageHandlerapi
一般,一些列的message handler被連接到一塊兒。第一個handler收到http request作一些處理,而後將request傳遞到下一個handler。在某時刻,response被創並返回。這種模式被稱爲delegating hanlder框架
在服務端,WebAPI管道使用一些內建的message handlers異步
HttpServer
從主機獲取requestHttpRoutingDispacher
基於路由分配requestHttpControllerDispacher
發送request到WebAPI的controller能夠在pipline中自定義message handlers,如圖,展現了兩個自定義的handlerasync
自定義message handler須要實現System.Net.Http.DelegatingHandler
接口,並重載SendAsync
方法。ide
Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken);
典型的實現經過一些流程:spa
base.SendAsync
將request傳遞到內部的handler(inner handler)一個簡單的例子:code
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頗有用)blog
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; } }
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框架會自動鏈接。接口
既能夠在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 );
跳過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); } }