希望給你3-5分鐘的碎片化學習,可能是坐地鐵、等公交,積少成多,水滴石穿,謝謝關注。
管道流
瞭解管道流機制,就能知道如何利用管道進行攔截,自定義封裝等高級操作,所以學習管道流機制對我們編碼有質的提高。那麼管道數據是如何流通的呢?如下圖所示,Request進入管道Middleware 1,疊加一層邏輯代碼到HttpContext(切確說是HttpContext的Response對象),然後調用next()進入到下一個管道Middleware 2,依次遞推,最後所有的邏輯代碼疊加完畢後返回前端。
管道實踐
實現自定義管道有兩種方法,使用IApplicationBuilder的Use和Run方法,他們的區別在下面會談到。
app.Use方法
這裏先了解Use方法的第一個重載,如下圖所示,他是一個類型爲委託的中間件(middleware)。
這個中間件同時攜帶一個next的RequestDelegate委託,可以實現調用下一個管道中間件,我們看下代碼實踐,如下所示,context從當前管道進來,處理後,通過next.Invoke()轉移到下一個管道,完成一個管道的生命週期。
其實我更喜歡截圖,因爲可以任意打標註,但是不方便拷貝,所以一起貼上代碼吧。
app.Use(async (context, next) => { await context.Response.WriteAsync("fisrt……"); await next.Invoke(); });
以上的用法,如果是新手可能不知其所以然,用沒問題,但是內部是如何實現的?不知道!其實這裏使用到了語言的高級特性委託,通過委託實現了開閉原則,也就是把管道的擴展開放出來,我們可以使用規定的app.Use方法,但是內部定義的委託參數類型,比如context,Fun<task>則對外屏蔽了實現。所以你看到的next.Invoke()已經封裝了具體的實現了,對於使用者,其實可以不用去管那麼多,拿來用即可。
app.Use還有另外一個重載,如下圖提示:這裏Func傳入一個RequestDelegate,返回一個RequestDelegate。不同於第一個重載,他沒有next.Invoke()的調用,而是之間返回一個RequestDelegate給app進行處理。
我們看下代碼實現,外層紅色框是傳入的管道,內部綠色框是返回的管道。
app.Run
app.Run和app.Use不同之處在於,app.Use可以調用下一個中間件的管道,app.Run不會,我們演示一段代碼。
app.Use(async (context, next) => { await context.Response.WriteAsync("<html><body>"); await context.Response.WriteAsync("<div>Inside middleware defined using app.Use</div>"); await next(); await context.Response.WriteAsync("</body></html>"); }); app.Run(async context => { await context.Response.WriteAsync("<div>Inside middleware defined using app.Run</div>"); });
//該管道會不會被打印呢? app.Use(async (context, next) => { await context.Response.WriteAsync("<html><body>"); await context.Response.WriteAsync("<div>Another Middleware defined using app.Use</div>"); await next(); await context.Response.WriteAsync("</body></html>"); });
如下圖所示,我們看到Run後面定義的第二個Use沒有打印出來,這是因爲Run不會調用隨後的管道導致的,所以我們一般習管性把Run方法放在所有管道的最後。
希望以上分享對你有幫助,我是張飛洪,入行10年有餘,人不堪其憂,吾不改其樂,謝謝您關注我的頭條