日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

.NET Core中间件的注册和管道的构建(2)---- 用UseMiddleware扩展方法注册中间件类

發布時間:2023/12/4 asp.net 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .NET Core中间件的注册和管道的构建(2)---- 用UseMiddleware扩展方法注册中间件类 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

0x00 為什么要引入擴展方法

有的中間件功能比較簡單,有的則比較復雜,并且依賴其它組件。除了直接用ApplicationBuilder的Use()方法注冊中間件外,還可以使用ApplicationBuilder的擴展方法UseMiddleware()注冊中間件。這種情況下可以注冊類型,這個方法會通過反射解析這個類型,并把它包裝成Func<ReuqestDelegate,RequestDelegate>然后調用Use()方法注冊。

遇到這種情況一般直覺上是通過繼承一個抽象類并實現其中的方法在寫一個中間件。不過.NET Core不是這么做的。中間件類使用約定而不是繼承來進行約束。這里說的約定就是約定原本的意思,例如約定好了中間件類中必須包含一個叫Invoke的方法,叫別的就不行,有重載也不行。因為中間件類沒有任何繼承上的約束,在注冊過程中就是通過反射去尋找名字為Invoke的方法,然后把它包裝成RequestDelegate的。這篇文章就是要說一下寫一個中間件類都有哪些約定以及中間件類的注冊。

0x01 一個最簡單的例子

先看一個中間件類的最簡單的例子:?

上一篇文章中說過了,中間件本質就是一個方法,這個方法接收一個HttpContext參數,返回Task。在上面這個中間件類中Invoke就是這個方法。為了能夠調用下一個中間件,當前中間件還需要保存下一個中間件的引用。這個引用是通過構造函數傳進來的,如果當前中間件不需要調用后面中間件的話,這個引用完全可以不保存。如果要注冊這個中間件,我們可以這樣做:

但如果我們這個中間件比較復雜,依賴很多其他模塊,那么我們在注冊的時候需要構造依賴模塊的實例,并在中間件類的構造函數中把這些依賴傳進去。這加強了中間件和依賴模塊之間的耦合度。為了能減少這種耦合,同時享受到依賴注入帶來的便利,提供了UseMiddleware<T>擴展方法來注冊中間件類T。

UseMiddleware擴展方法會找到上面中間件類中的Invoke方法,創建上面類的實例,在創建實例時遇到需要注入的類型會嘗試注入,然后把Invoke方法包裝為ReuqestDelegate,進而包裝為Func<RequestDelegate,RequestDelegate>,然后通過ApplicatonBuilder的Use方法(上篇文章講過了)注冊到IList<Func<RequestDelegaet,RequestDelegate>中。

從上面的SimpleMiddleware我們可以看到這個類沒有任何顯示的繼承關系,那么我們在寫一個中間件類時需要注意哪些約束呢?我們只要看一下UseMiddleware注冊中間件的過程就明白了。下面是對UseMiddleware()方法的分析,對代碼分析不感興趣的可以跳過直接看后面的結論和測試。

0x02 擴展方法注冊中間件類的過程

使用UseMiddleware<T>擴展方法注冊中間件類T主要包含以下幾個關鍵步驟:

1.找到中間件類的Invoke方法。UseMiddleware方法會通過反射獲取注冊的中間件類的所有public且非static的方法列表,然后從其中找出名字叫Invoke的方法,確認Invoke方法沒有重載,確認Invoke方法返回Task,確認Invoke方法第一個參數是HttpContext,最后這兩個檢查是為了能把Invoke方法包裝為RequestDelegate。

2.選取最佳構造函數。把下一個中間件的引用next插入到從UseMiddleware傳入的參數列表的第一個,作為給定的參數列表。

然后獲取中間件類的所有構造函數,從給定的參數列表中依次取出參數,和構造函數的參數進行類型匹配,匹配最多的構造函數選為最佳構造函數。匹配相同的以代碼中排在前面的構造函數為準(這其中省略了很多匹配最佳構造函數的細節,感興趣的可以自行查看代碼)。

值得注意的是如果存在給定的參數列表中存在某個參數P,在當前構造函數參數列表中找不到與之匹配的類型,那么這個構造函數不能作為最佳構造函數。也就是說選中的最佳構造函數的參數列表必須要是給定參數列表的超集。剛剛上面也說了,下一個中間件next被插入到了給定參數列表的第一個,因此選中的最佳構造函數參數中必須包含參數RequestDelegate。如果所有構造函數都不包含RequestDelegate,那么會拋出異常。

3.構造中間件類的實例。找到了最佳構造函數后,接下來就使用該構造函數構造中間件類的實例。對于構造函數中的所有參數,能夠從給定的參數列表中找到類型匹配的,從給定的參數列表中獲取參數。從參數列表中找不到的,則嘗試從依賴注入容器中獲取,依賴注入容器中也找不到的檢查是不是有默認值,默認值也沒有就拋出異常。

4.實例構造完成后,如果Invoke方法只有一個參數(HttpContext)會把這個實例的Invoke方法包裝為RequestDelegate,進而包裝為Func<RequestDelegate,RequestDelegate>然后使用Use方法注冊。如果有多個參數,不符合RequestDelegate約束,則對Invoke進行二次包裝以符合RequestDelegate。在二次包裝中會嘗試從依賴注入容器中獲取Invoke參數中的依賴。

0x03一些結論

下面總結一下中間件類的一些約定,主要是基于對代碼的理解,有錯誤或不全的地方請指正。

關于中間件的方法:

1.中間件的方法必須叫Invoke,且為public,非static。

2.Invoke方法第一個參數必須是HttpContext類型。

3.Invoke方法必須返回Task。

4.Invoke方法可以有多個參數,除HttpContext外其它參數會嘗試從依賴注入容器中獲取。

5.Invoke方法不能有重載。

?

關于構造函數:

1.構造函數必須包含RequestDelegate參數,該參數傳入的是下一個中間件。

2.構造函數參數中的RequestDelegate參數不是必須放在第一個,可以是任意位置。

3.構造函數可以有多個參數,參數會優先從給定的參數列表中找,其次會從依賴注入容器中獲取,獲取失敗會嘗試獲取默認值,都失敗會拋出異常。

4.構造函數可以有多個,屆時會根據構造函數參數列表和給定的參數列表選擇匹配度最高的一個。?

個人建議,真的僅僅是個人的一些建議:

1.除及特殊情況外只保留一個構造函數,以省去多余的構造函數匹配檢查。

2.在構造函數中注入所需依賴而不是Invoke中。

3.關于構造函數參數的順序,把RequestDelegate放在第一個;之后是UseMiddleware方法中給出的參數,而且構造函數中參數順序和給定參數列表中的順序最好也相同;然后是需要注入的參數;最后是有默認值的參數。以上除了默認值參數必須放在最后外其余的順序都不是必須的,但按照上面的順序會比較清晰,而且能使實例創建的開銷最小。

4.Invoke方法只保留一個HttpContext參數。這樣可以省去對Invoke方法的二次包裝。

5.進一步擴展ApplicationBuilder,創建語義更加明確的方法代替Use/UseMiddleware,例如UseMVC、UseStaticFiles。

其中1中所說的及特殊的情況,我能想到的就是給UseMiddleware提供不同的參數列表,進而匹配到不同的構造函數創建實例。具體使用場景沒有想到。

0x04 測試

上篇文章中我們寫過一個記錄后面所有中間件耗時的中間件。當時直接用Use方法注冊的。現在我們把它寫為一個中間件類,并且把計時功能寫為一個StopWatch類,并添加到依賴注入容器中。

下面是計時器類的代碼:

下面是中間件類的代碼

下面是向依賴注入容器中添加StopWatch

下面是使用UseMiddleware擴展方法添加TimeMiddleware中間件代碼

當然,也可以不把StopWatch添加到依賴注入容器中,而是在UserMiddleware方法中直接給出參數。

如果既在依賴注入容器中添加了StopWatch,又在UseMiddleware注冊時提供了StopWatch,那么按照參數匹配順序最終使用的是注冊時提供的StopWatch。

運行一下可以看到與上篇文章同樣的效果。

0x05 寫在最后

UseMiddleware方法使注冊中間件變得容易,同事也減小了中間件和其它依賴模塊間的耦合。不過不管哪種擴展方法,最終都是通過Use方法實現中間件的注冊。下一篇文章將寫一下注冊中間件的其它擴展方法Map、MapWhen和Run。

原文地址:http://www.cnblogs.com/durow/p/5748124.html


.NET社區新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關注

總結

以上是生活随笔為你收集整理的.NET Core中间件的注册和管道的构建(2)---- 用UseMiddleware扩展方法注册中间件类的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。