.NET Core中間件的註冊和管道的構建(1)---- 註冊和構建原理

.NET Core中間件的註冊和管道的構建(1)---- 註冊和構建原理

0x00 問題的產生

管道是.NET Core中很是關鍵的一個概念,不少重要的組件都以中間件的形式存在,包括權限管理、會話管理、路由等。因此搞明白中間件是如何註冊並最終構建成管道的很重要。園子裏不少先驅早已經開始了這方面的研究學習,也寫了不少文章,不過我看了後有些地方還不是特別明白。畢竟每一個人都是不一樣的,有些內容做者以爲是常識不須要多寫的地方對我來講可能就是個盲區。幸虧.NET Core整個項目都是開源的,找到源碼看了下解決了我心中的困惑。同時寫篇博客記錄一下,也算一個補充,若是你們看了能有所收穫那就更好了。原本是想一片文章寫完的,後來發現太長了,因此分了兩篇。這是第一篇,主要說一下中間件的註冊和管道的構建原理,後面一篇寫一下注冊中間件類的原理和寫中間件類須要注意的約定和特性。html

0x01 中間件的註冊

管道的構建主要包含中間件註冊和把註冊的中間件構建成管道。先來講中間件的註冊。學習

什麼是中間件。說簡單一點中間件就是一個方法,傳入一個HttpContext類型參數,返回Task。參數HttpContext中包含了HTTP請求和響應等相關信息,中間件能夠讀取/修改其中的部份內容,並決定是否讓下一個中間件繼續處理這個HttpContext。這個方法包裝爲一個委託RequestDelegate。測試

 

爲了讓中間件有權決定是否讓下一個中間件繼續處理HttpContext,當前中間件須要下一個中間件的引用。因此在註冊中間件的時候須要註冊爲Func<RequestDelegate,RequestDelegate>的形式,其中傳入的參數指的是下一個中間件,返回的是咱們註冊的中間件,傳入的參數在ApplicationBuilder在執行Build()方法構建管道時傳入(後面會看到)。因此爲了方便理解,不那麼嚴謹的來看,中間件以Func<NextMiddleware,ThisMiddleware>的形式註冊並存儲在一個列表中。ui

 

 能夠經過ApplicationBuilder的Use方法註冊中間件spa

0x02 管道的構建

管道的構建就是把Func<RequestDelegate,RequestDelegate>列表串在一塊兒。用第一個Func的返回值做爲第二個Func的參數,第二個Func的返回值做爲第三個Func的參數,依次類推。最終返回最後一個Func返回的RequestDelegate(中間件)。管道工做時最後一個RequestDelegate能夠決定是否調用倒數第二個RequestDelegate,倒數第二個RequestDelegate能夠決定是否調用倒數第三個RequestDelegate,依次類推直到調用第一個RequestDelegate。這中間有兩個問題:3d

第一個是這樣構建管道,中間件的順序和註冊的時候是相反的,因此在構件時首先把列表_components.Reverse()以保證正確的中間件順序。component

第二個問題是構建第一個中間件時沒有RequestDelegate能夠傳入,因此須要構建一個把狀態碼設置爲404的中間件做爲最開始的RequestDelegate傳入。固然在構建完成後這個中間件是存在於管道最末端的。這樣管道構建就算完成了。Build()代碼以下:htm

0x03 測試

構建完成後的管道和中間件以下圖:中間件

這是微軟官方的圖,不少文章中也引用過。從這張圖中能夠看出來中間件經過調用next()啓動下一個中間件。若是中間件不調用next()那麼它以後的全部中間件就都不會調用了。除此以外還有一個細節須要注意,就是next()的調用並非必需要放到最後的。也就是說能夠先調用後面的中間件,等後面的中間件調用完成後在執行一些操做(圖中的more logic)。blog

下面來分別進行測試,正常創建一個.NET Core MVC Web項目。

測試1:註釋掉Configure()中的全部內容,而後依次註冊中間件:

運行後結果爲:

這個測試印證了以前代碼中看到的中間件的註冊順序就是調用順序。

 


 

測試2:註釋掉Middleware1的next調用,其它保持不變。這樣Middleware1就不會調用Middleware2,Middleware2以及以後的全部中間件都沒法調用。

運行結果變爲:

這個測試說明Middleware1不調用next()的話後面的Middleware2和Middleware3都沒有被調用。

 


 

測試3:把Configure()方法修改以下:

咱們在最開始註冊一箇中間件記錄當前時間,而後調用後面全部中間件,最後返回時計算後面全部中間件執行所消耗的時間。爲了看上去更明顯後面又註冊了一箇中間件強制睡眠100毫秒。須要注意的是強制睡眠的中間件要註冊在MVC以前,由於MVC結束後就直接返回了,不會調用後面的中間件了。

運行結果爲:

這個測試說明對下一個中間件的調用不必定非要放到最後,能夠先調用後面中間件,等後面全部中間件調用完成後再繼續處理。

0x04 寫在最後

這篇文章主要討論了中間件的註冊和管道構建的一些原理,實際上對於複雜一點的中間件來講,通常都有更復雜的邏輯並對其它組件依賴。下一篇將討論把中間件寫成一個類並注入依賴的方法和原理。

此外這篇文章主要是我我的的一些理解和直覺。。。好吧真的有些是直覺,能力有限,博客園大牛衆多,有錯誤的地方你們嘴下留情啊。

0x05 相關文章

.NET Core中間件的註冊和管道的構建(1)---- 註冊和構建原理

.NET Core中間件的註冊和管道的構建(2)---- 用UseMiddleware擴展方法註冊中間件類

.NET Core中間件的註冊和管道的構建(3) ---- 使用Map/MapWhen擴展方法

 


更多內容歡迎訪問個人博客:http://www.durow.vip

相關文章
相關標籤/搜索