1. 程式人生 > >【乾貨】.NET WebApi HttpMessageHandlerg管道

【乾貨】.NET WebApi HttpMessageHandlerg管道

訊息攔截器是一個類,接收 HTTP request並返回 HTTP response,Message handler 繼承自抽象類 HttpMessageHandler,那麼學習訊息過濾器之前你應該瞭解下webapi的執行流程。

 

以上是webapi的執行流程,先是從response開始執行一套順序之後通過network再回到了Request,其中經過了messageHandler,因為它是webapi架構中給我們可以自定義handler的地方,這和以往的webform差不多。都是基於http請求的。

有可能你會說這和過濾器Aop模式差不多啊,但你可以看完這篇文章之後再比比誰強大,當然它兩者的用處都不同。

那訊息攔截器有什麼用呢,聽名字我覺得你應該就知道是怎麼回事,它是可以在客戶端請求用修改請求資訊的中間層,再次其中我們可以修改;新增 response headers,在到達 controller 之前,進行引數驗證!

自定義  MessageHandler 需要繼承 System.Net.Http.DelegatingHander 並且過載 SendAsync 方法

public class MessageHandler1 : DelegatingHandler
{
  protected async override Task<HttpResponseMessage> SendAsync(
    HttpRequestMessage request, CancellationToken cancellationToken)
  {
    Debug.WriteLine("hello");
    var response = await base.SendAsync(request, cancellationToken);
    Debug.WriteLine("bye");
    return response;
  }
}

 這是最基本的處理流程,當然自此期間你需要去新增配置。

public static class WebApiConfig
{
  public static void Register(HttpConfiguration config)
  {
    config.MessageHandlers.Add(new MessageHandler1());
    config.MessageHandlers.Add(new MessageHandler2());
  }
}

 在訊息攔截器中常見的是要判斷使用者資訊,因為像ActionFilterAttribute、ApiControllerActionInvoker、ExceptionFilterAttribute 這些都是在action之前的,那我們就要在之前進行判斷。

 在HttpRequestMessage中包含了以下屬性,這些你都是可以改的。

 如何操作header?

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

 首先呼叫sendAsync將請求傳遞給inner handler,讓它返回響應資訊,但是它在建立非同步的時候,響應訊息是不可用的。

只能全域性去配置嗎?

//路由中指定Message Handler
        config.Routes.MapHttpRoute(
            name: "Route2",
            routeTemplate: "api2/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional },
            handler: new MessageHandler2() // per-route message handler
     );

這時MessageHandler2替換預設的HttpControllerDispatcher。這個栗子中MessageHandler2建立響應,匹配“Route2”的請求永遠不會轉到控制器。這使我們可以使用自己的自定義響應替換整個Web API控制器機制。

不知道你有沒有想過,如果你的webapi不支援一些特殊的請求,你該怎麼辦呢,這個時候呵呵,你應該知道了吧!

在這個例項中我們定義了一個集合,在post請求中,一定不是get,那麼就有可能是put 或者delete等待的請求頭,那麼我們可以獲取進行修改。

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.InvariantCultureIgnoreCase))
                    {
                        request.Method = new HttpMethod(method);
                    }
                }
                return base.SendAsync(request, cancellationToken);
            }
        }

  那我們可以獲取請求頭,如何進行新增呢??

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呼叫內部訊息處理器返回相應結果,base.SendAsync之前是不可響應獲取訊息的。

  這個示例使用了await關鍵字,以便在SendAsync完成之後非同步地執行任務。

  protected override Task<HttpResponseMessage> SendAsync( 
        HttpRequestMessage request, CancellationToken cancellationToken) 
    { 
        return base.SendAsync(request, cancellationToken).ContinueWith( 
            (task) => 
            { 
                HttpResponseMessage response = task.Result; 
                response.Headers.Add("X-Custom-Header", "This is my custom header."); 
                return response; 
            } 
        ); 
    }