天天看點

OWIN的了解和實踐(三) –Middleware開發入門

上篇我們談了Host和Server的建立,但Host和Server無法産出任何有實際意義的内容,真正的内容來自于加載于Server的Middleware,本篇我們就着重介紹下Middleware的開發入門.

Middleware是什麼

如果把HTTP互動了解為一次答題活動,那麼Request是問題,Response就是答案,Server是課堂,Middleware就是參與者,注意我這裡用的是參與而不是解答,因為我們允許有些Middleware不給出答案.

Middleware有什麼資源

要參與答題活動就必須有知識,也就是資源.在OWIN規則中,所有Middleware隻能獲得并影響一個資源,這個就是OWIN Context,有一個Microsoft.Owin. IOwinContext接口定義了這個上下文的标準. 我們來看下這個裡面有什麼東西.

OWIN的了解和實踐(三) –Middleware開發入門

這個上下文接口中 提供的資源,是Middleware進行運作的關鍵:

  • Authentication : 擷取可在目前請求上使用的身份驗證(Identity)中間件功能。通過這個屬性可以非常便捷在任何Middleware中通路目前的Identity資訊.當然至少一個Identity中間件需要被加載,否則這個屬性中的内容沒有意義.
  • Environment: 擷取已包裝的 OWIN 環境。它本質是一個資料字典,一個Middleware利用Key放入一個資訊,而另外一個Middleware根據Key拿出來使用. 和Session異曲同工.
  • Request: 擷取可公開特定于請求的屬性的包裝。Middleware從這裡了解我們的提問者(Request)提供了那些資訊.
  • Response : 擷取可公開特定于響應的屬性的包裝。Middleware通過這個屬性可以給出,影響或者改變我們的Response(答案),當然它也可以不做任何調整.

Middleware到底做什麼,怎麼做

簡單來說,Middleware可以做什麼怎麼做可以歸結為以下幾點:

  • 獲得OWIN Context和它内部封裝的所有資訊.
  • 從Request中擷取請求的所有資訊.
  • 從Environment中擷取其他Middleware共享的資源,以便于和其他Middleware互動,或者使用其他Middleware提供的功能.
  • 從Authentication中擷取目前的身份驗證資訊和結果.
  • 通過Response給出,影響,甚至改變Server即将發出的”答案”

Middleware有哪幾種類型

剛剛我們說了,Middleware不一定是問題的解答者, 他們有前後的順序和各自回答問題的方式,根據他們的參與方式,我把他們分成3種情況:

OWIN的了解和實踐(三) –Middleware開發入門
  1. 解答者: 了解問題的内容(Request),給出最終答案(Response),一般不需要後續解答者的參與. 比較典型是解答者是WebApi和StaticFiles(靜态檔案).
  2. 參與者: 了解問題的内容,給出一定的資源(Environment)供其他參與者使用,本身一般不參與解答, 有可能在答案中加入一些附加資訊.比較典型的有Session和Identity.它們一般會加入一些Cookie但不影響Response實體内容.
  3. 監控者: 在其他參與者開始處理或者處理完畢的時候對目前的Context中的資訊進行處理,它也一般不參與解答,有可能在答案中加入一些附加資訊. 比較典型的有Logging, Diagnostics.

如何建立Middleware

建立一個的Middleware分以下幾個步驟:

  1. 引入Microsoft.Owin包
  2. 建立一個類
  3. 使這個類繼承Microsoft.Owin.OwinMiddleware
  4. 實作這個類的構造函數
  5. 覆寫并實作父類的Invoke函數

一個最為典型的實作如下

using Microsoft.Owin;
    using System.Threading.Tasks;

    /// <summary>
    /// Middleware類必須繼承Microsoft.Owin.OwinMiddleware
    /// </summary>

    public class SampleMiddleware : OwinMiddleware
   {
       public SampleMiddleware(OwinMiddleware next)
          : base(next)
        {
            //構造函數
        }

        public override Task Invoke(IOwinContext context)
        {
            //中間件的實作代碼
            return Next.Invoke(context);
        }
}      

絕大部分Middleware需要預設一些屬性,這些屬性可以通過改造構造函數來實作:

object m_Options;
        public SampleMiddleware(OwinMiddleware next,object options)
            : base(next)
        {
            //引入參數類,并可以再類中使用
            m_Options = options;
        }      

當然類似的options參數可以有多個.

以上的Middleware實作其實是沒有意義的,因為沒有做任何事情,下面我将給出一個”給出答案”的簡單實作,根據上面的描述,我在下面僅僅給出Invoke函數的内容.

這裡再插一句,上述代碼中的next或Next指的是排在這個Middleware之後的另一個Middleware,而context就是我們上面所說的上下文資訊.

一個簡單的Middleware範例

剩下的工作,就是在Invoke函數中實作目前Middleware的功能,這裡給出一個非常簡單的實作,來做出一個最簡單的功能: 輸入結尾為\tick的URL,傳回一個純文字的Response,裡面包含目前伺服器時間的Tick資訊.

public override Task Invoke(IOwinContext context)
      {
            PathString tickPath = new PathString("/tick");
            //判斷Request路徑為/tick開頭
            if (context.Request.Path.StartsWithSegments(tickPath))
            {
                string content = DateTime.Now.Ticks.ToString();
                //輸出答案--目前的Tick數字
                context.Response.ContentType = "text/plain";
                context.Response.ContentLength = content.Length;
                context.Response.StatusCode = 200;
                context.Response.Expires = DateTimeOffset.Now;
                context.Response.Write(content);
                //解答者告訴Server解答已經完畢,後續Middleware不需要處理
                return Task.FromResult(0);
            }
            else
             //如果不是/tick路徑,那麼傳遞後續Middleware處理
            return Next.Invoke(context);

        }      

這裡提幾個要點:

  • PathString是Miscrosoft.Owin下一個類,封裝了URL處理的一些功能.
  • Task.FromResult(0) 表示一個空的Task,說明該Middleware在某些情況下不再觸發後續的Middleware運作—也就是”到此為止”.
  • 最後Next.Invoke(context)是一個非常标準的實作,把上下文傳遞下一個Middleware繼續處理—相當于”交出接力棒”.
  • 這個Middleware是一個标準的解答者.它給出了”/tick”這個問題的最終答案.

如何使用Middleware

這裡需要回到我的上一篇博文, Host和Server開發, 在那裡面,我說到目前的Startup函數是空的,說明沒有加載任何Middleware,而現在我們需要在那個函數裡面加載我們開發的Middleware了,代碼很簡單:

private static void Startup(Owin.IAppBuilder app)
        {
            //加載Sample Middleware
            Console.WriteLine("Sample Middleware loaded...");
            app.Use<SampleMiddleware>();
        }      

注意2點:

  • 保證已經加入了 using Owin;
  • SampleMiddleware的構造函數是僅有一個OwinMiddleware參數的版本,如果有附加參數,請加到Use函數的參數清單裡面去.

好了,聯合上一篇博文的代碼,編譯運作.我們能夠看到如下輸出界面:

OWIN的了解和實踐(三) –Middleware開發入門

(注意:很多機器需要管理者權限運作VS,才能正常運作該程式)

打開浏覽器,通路http://localhost:9000/tick

我們看到了一個tick. 這就是這個中間件傳回的結果.而其他位址依然會沒有任何傳回,這是因為并沒有任何其他Middleware來處理其他的情況.

        當然,基于OWIN架設的體系,我們可以開發更加複雜的Middleware,下一篇,我将會進一步給出三個比較複雜的Middleware實作:  StaticFile, Session, Logging; 來幫助大家進一步了解,解答者,參與者和監控者的概念.同時也深入了解Middleware的運作機制.

軟體開發,項目管理,開發管理,團隊管理.

CMMI,PMP