.NET Core基礎:白話管道中間件
在Asp.Net Core中,管道往往伴隨著請求一起出現。客戶端發起Http請求,服務端去響應這個請求,之間的過程都在管道內進行。
舉一個生活中比較常見的例子:旅游景區。
我們都知道,有些景區大門離景區很遠,我們需要經過層層關卡才能到達景區。
我的請求最終就是去到景區,去到景區的整個過程就是管道,景區就是服務器,層層關卡就是一個個中間件了,比如:門票、停車費、擺渡費等等。
如果其中任何一個中間件卡殼了,比如我沒買門票,那別人肯定是不讓我進去,這就是管道短路了。
Asp.Net Core 請求管道包含一系列Http請求委托(RequestDelegate),依次調用。
微軟給的圖示:

.Net Core服務
在解釋管道的使用方法之前,我們先來準備一個Asp.Net Core服務。
創建一個.Net Core控制臺應用程序,并實現如下代碼,一個簡單的使用 Kestrel 托管的服務就完成了:
internal class Program{static void Main(string[] args){new WebHostBuilder().UseKestrel().UseStartup<Startup2>().Build().Start();Console.ReadLine();}}public class Startup{public void Configure(IApplicationBuilder app){}}

這也是.Net Core的優點之一,只選擇我們需要的,摒棄那些多余的功能。優點是優點,一般開發中也犯不上這樣去做。
Kestrel 托管默認監聽端口:5000
管道中間件
微軟這邊內置了三個擴展函數供我們構建自己的中間件:
-
Use
-
Map
-
Run
其中Use和Map函數還提供了對應的分支擴展:UseWhen、MapWhen、UseMiddleware。下面我們一個個來解釋。
app.Use
Use 是最常用的一種模式,承接上一個請求并執行下一個請求的任務
public void Configure(IApplicationBuilder app){app.Use(async (context, next) =>{Console.WriteLine("middleware1");await next.Invoke();});app.Use(async (context, next) =>{Console.WriteLine("middleware2");});}
app.UseWhen
UseWhen在Use的基礎上提供了條件分支的功能
app.UseWhen(context =>// 判斷請求路徑的開頭是否是/hcontext.Request.Path.StartsWithSegments(new PathString("/h")),c => c.Use(async (context, next) =>{Console.WriteLine("middleware1");await next.Invoke();}));app.Use(async (context, next) =>{Console.WriteLine("middleware2");});


app.Map
Map我們可以理解成專為請求路徑擴展的分支中間件,可以根據請求路徑去處理對應分支邏輯,與上面的UseWhen例子效果類似,但更加方便。
app.Map("/h", _app =>{_app.Use(async (context, next) =>{Console.WriteLine("hello world");});});
app.MapWhen
MapWhen與UseWhen類似,都是在請求上下文的基礎上去擴展分支,比Map更加靈活。
app.MapWhen(context => { return context.Request.Query["name"] == "tony"; }, _app => {_app.Use(async (context, next) => {context.Response.ContentType = "text/plain; charset=utf-8";await context.Response.WriteAsync("i 服了 you");});});
app.Run
Run一般用于斷路或請求管道的末尾,不會將請求傳遞下去
app.Run(async context =>
{
await context.Response.WriteAsync("hello world");
});
UseMiddleware
將一個完整的類添加到管道中間件,也就是將上面的請求委托,用類以及函數的形式替代了,便于我們的代碼管理。
app.UseMiddleware<DotnetboyMiddleware>();public class DotnetboyMiddleware{private readonly RequestDelegate _next;private readonly string _name;public DotnetboyMiddleware(RequestDelegate next, string name){_next = next;_name = name;}public Task Invoke(HttpContext context){context.Response.WriteAsync($"my name is {_name}").Wait();return this._next(context);}}
微軟內置的一些管道中間件擴展函數就介紹完了,下面我們實現一下微軟實例圖示中的效果:
public void Configure(IApplicationBuilder app){app.Use(async (context, next) =>{Console.WriteLine("middleware1 : in");await next.Invoke();Console.WriteLine("middleware1 : out");});app.Use(async (context, next) =>{Console.WriteLine("middleware2 : in");await next.Invoke();Console.WriteLine("middleware2 : out");});app.Run(async context =>{Console.WriteLine("Hello World");await context.Response.WriteAsync("Hello World");});}


從上面的例子中我們可以看到,中間件都是由上而下依次執行,由每個中間件決定是否繼續執行下一個中間件,最終到響應結果。
如果哪個中間件決定不往下執行,那通道也就短路了,比如我們去掉 middleware2 的 await next.Invoke();
執行到 Console.WriteLine("middleware2 : out"); 就短路了,此路不通,原路返回。

因為管道中間件執行邏輯的關系,我們在實際開發中要注意兩點:
-
1、謹慎使用管道短路
-
2、注意中間件的使用順序,比如:路由中間件肯定是要在認證中間件前面執行,有中間件需要訪問文件,在此之前就必須先執行開放靜態文件的中間件
本文來自博客園,作者:{春光牛牛,yak},轉載請注明原文鏈接:http://www.rzrgm.cn/yakniu/p/17011279.html
歡迎各位大佬們評論指正
QQ討論群:610129902


浙公網安備 33010602011771號