ASP.NET Web API 管道模型


ASP.NET Web API 管道模型

前言

ASP.NET Web API是一個獨立的框架,也有着自己的一套消息處理管道,不管是在WebHost宿主環境還是在SelfHost宿主環境請求和響應都是從消息管道經過的,這是必經之地,本篇就為大家簡單的介紹一下ASP.NET Web API框架中的管道對象模型。

 

ASP.NET Web API路由、管道

  • ASP.NET Web API 開篇介紹示例
  • ASP.NET Web API 路由對象介紹
  • ASP.NET Web API 管道模型
  • ASP.NET Web API selfhost宿主環境中管道、路由
  • ASP.NET Web API webhost宿主環境中管道、路由

 

 

管道模型介紹

HttpMessageHandler消息處理程序(基類)

    public abstract class HttpMessageHandler : IDisposable
    {
        protected HttpMessageHandler();
        public void Dispose();
        protected virtual void Dispose(bool disposing);
        protected internal abstract Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
    }

上面的代碼中定義的是消息處理程序基類,在管道中的每一個消息處理部分都是繼承自它。

並且定義了一個會執行異步操作的SendAsync()方法,這個方法也是串聯管道中各個消息處理程序的一個入口,但是並不是靠它來串聯。

 

DelegatingHandler消息處理程序(基類)

    public abstract class DelegatingHandler : HttpMessageHandler
    {
        protected DelegatingHandler();
        protected DelegatingHandler(HttpMessageHandler innerHandler);
        public HttpMessageHandler InnerHandler { get; set; }

        protected override void Dispose(bool disposing);
        protected internal override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
    }

這里的DelegatingHandler繼承自HttpMessageHandler類型,而且DelegatingHandler也是抽象類型,DelegatingHandler類型並不是就是簡單的繼承,而是對基類進行了擴展,使之變成一個帶指向箭頭(對象引用)的對象類型也就是InnerHandler屬性,InnerHandler屬性的值就是在當前這個消息處理程序的下一個消息處理程序,DelegatingHandler類型對基類的擴展,HttpMessageHandler類型我感覺它的存在就是一個規范,從管道中的第一個處理程序開始一直到最后一個,除了最后一個消息處理程序,其他的都是DelegatingHandler類型的子類(當然也是HttpMessageHandler的子類),最后一個消息處理程序是直接繼承自HttpMessageHandler類型,因為它是最后一個處理程序了不必要有指向下一個處理程序的屬性,這種對職責的划分真的很優美,說不出好在哪就是覺得漂亮。

 

HttpServer消息處理程序(實現類-管道頭)

public class HttpServer : DelegatingHandler
    {
        public HttpServer();
        public HttpServer(HttpConfiguration configuration);
        public HttpServer(HttpMessageHandler dispatcher);
        public HttpServer(HttpConfiguration configuration, HttpMessageHandler dispatcher);
        public HttpConfiguration Configuration { get; }
        public HttpMessageHandler Dispatcher { get; }

        protected override void Dispose(bool disposing);
        protected virtual void Initialize();
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
    }

HttpServer類型繼承自DelegatingHandler類型,是作為管道中第一個消息處理的,要說明的是重載的這些構造函數,如果只是采用默認的構造函數的話,HttpConfiguration類型的參數默認的就是實例化HttpConfiguration類型,而HttpMEssageHandler類型的參數默認的是實例化HttpRoutingDispatcher類型的消息處理器,並且是賦值到Dispatcher屬性的,是作為管道中最后一個消息處理器的(真正的操作實際不是它,后面篇幅會有講到)。

 

HttpRoutingDispatcher消息處理程序(實現類-管道尾)

    public class HttpRoutingDispatcher : HttpMessageHandler
    {
        // Fields
        private readonly HttpConfiguration _configuration;
        private readonly HttpMessageInvoker _defaultInvoker;

        // Methods
        public HttpRoutingDispatcher(HttpConfiguration configuration);
        public HttpRoutingDispatcher(HttpConfiguration configuration, HttpMessageHandler defaultHandler);
        private static void RemoveOptionalRoutingParameters(IDictionary<string, object> routeValueDictionary);
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
    }

HttpRoutingDispatcher類型繼承自HttpMessageHandler類型,上面也說到過它是作為在管道中最后一個消息處理器的,說是可以這么說,但是真正執行的卻不是它,而是在執行重載的構造函數的時候會默認的生成HttpControllerDispatcher類型作為HttpMessageHandler類型的構造函數參數,這里就不對它進行過多的闡述了,后面的篇幅自然會說明的很詳細。

下面我們來看一下ASP.NET Web API管道的大概示意圖。

圖1

(藍色線條表示請求,紅色線條表示響應)

這樣的示意圖說明的不是太清晰下面我們用《ASP.NET Web API 開篇介紹示例》中的SelfHost環境下的示例來演示一下,這樣大家自然就會清楚這個流程了。

首先我們定義一個消息處理器類型命令為CustomDelegatingHandler,並且繼承自DelegatingHandler類型。示例代碼如下

代碼1-1

    public class CustomDelegatingHandler : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
        {
            Console.WriteLine(request.RequestUri.OriginalString + "____" + request.Method.Method);

            Task<HttpResponseMessage> responseMessage = base.SendAsync(request, cancellationToken);

            Console.WriteLine(responseMessage.Result.RequestMessage.Method.Method);

            return responseMessage;
        }
   }

隨之我們在SelfHost環境下的服務端在注冊路由之后注冊剛才我們新建的消息處理程序對象,示例代碼如下:

代碼1-2

        static void Main(string[] args)
        {
            HttpSelfHostConfiguration selfHostConfiguration =
                new HttpSelfHostConfiguration("http://localhost/selfhost");
            using (HttpSelfHostServer selfHostServer = new HttpSelfHostServer(selfHostConfiguration))
            {
                selfHostServer.Configuration.Routes.MapHttpRoute(
                    "DefaultApi", "api/{controller}/{id}", new { id = RouteParameter.Optional });
                RegistrationMessageHandler(selfHostServer.Configuration);

                selfHostServer.OpenAsync();

                Console.WriteLine("服務器端服務監聽已開啟");
                Console.Read();
            }

        }
        static void RegistrationMessageHandler(HttpConfiguration httpconfiguration)
        {
            httpconfiguration.MessageHandlers.Add(new HttpMessageHandlers.CustomDelegatingHandler());
        }

 

 

在注冊完畢,並且服務器已經啟動開啟請求監聽,客戶端也隨之發出請求之后,我們再來看一下客戶端發出的請求以及類型,如下圖。

圖2

這個時候我們再來看一下服務端管道處理情況,如下圖。

圖3

每一個紅框圈中的部分都表示着一個請求和響應的流程跟圖2中的所有請求是對應的,可以從代碼1-1中就可以看出輸出的內容。

如果說這樣的示例並不不明顯,不能讓人很清楚明白的了解管道的執行過程以及順序,那我們定義兩個處理程序,並且修改代碼1-1,示例代碼如下:

代碼1-3

    public class CustomDelegatingHandler : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
        {
            Console.WriteLine(this.GetType().Name + ":" + request.RequestUri.OriginalString + "____" + request.Method.Method);

            Task<HttpResponseMessage> responseMessage = base.SendAsync(request, cancellationToken);

            Console.WriteLine(this.GetType().Name + ":" + responseMessage.Result.RequestMessage.Method.Method);

            return responseMessage;
        }
    }

    public class CustomDelegatingHandler_1 : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
        {
            Console.WriteLine(this.GetType().Name + ":" + request.RequestUri.OriginalString + "____" + request.Method.Method);

            Task<HttpResponseMessage> responseMessage = base.SendAsync(request, cancellationToken);

            Console.WriteLine(this.GetType().Name + ":" + responseMessage.Result.RequestMessage.Method.Method);

            return responseMessage;
        }
}

隨之我們注冊管理處理程序的地方也要新增一個消息處理程序,示例代碼如下:

代碼1-4

        static void RegistrationMessageHandler(HttpConfiguration httpconfiguration)
        {
            httpconfiguration.MessageHandlers.Add(new HttpMessageHandlers.CustomDelegatingHandler());
            httpconfiguration.MessageHandlers.Add(new HttpMessageHandlers.CustomDelegatingHandler_1());
        }

這個時候按照圖2之前的那段說明操作,再看一下服務端的管道處理情況,請求還是那些個請求,看下示意圖如下:

圖4

(紅框部分的代表就是跟上面所說的一樣,一個請求一個響應管道所對應的處理情況)

最后再看一下圖5結合圖4,這樣更好更容易理解。

圖5

 

 

作者:金源

出處:http://www.cnblogs.com/jin-yuan/

本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM