中間件是匯集到以處理請求和響應的一個應用程序管道的軟件。 每個組件:
- 可以選擇是否要將請求傳遞到管道中的下一個組件。
- 之前和之后調用管道中的下一個組件,可以執行工作。
使用請求委托來生成請求管道。 請求委托處理每個 HTTP 請求。
請求中使用委托來配置運行,映射,和使用擴展方法。 一個單獨的請求委托,它可將指定的在行作為匿名方法 (稱為中,線中間件),或可以在可重用的類中定義它。 這些可重用的類和行在匿名方法中間件,或中間件組件。 在請求管道中的每個中間件組件負責調用管道中的下一個組件,或如果相應短路鏈。
使用 IApplicationBuilder 創建中間件管道
ASP.NET 核心請求管道由請求委托,調用一次是在另一個,如圖所示 (執行如下所示的黑色箭頭的線程) 的順序組成:
我們可以鏈接多個請求委托連同app.use。 next
參數表示管道中的下一步委托。我們一共有兩種辦法構建管道:
然后執行dotnet build生成項目后執行 dotnet run 來運行我們我們的程序
如果我們在第二步的時候不調用Invoke會怎樣?我們先執行 dotnet watch run
然后 我們再修改代碼:
IApplicationBuilder是用來構建管道的,我們可以通過Use來注冊中間件,同時可以傳遞給我們一個next的Deletegate的委托。在這個情況下,我們可以調用下一步中間件的委托,如果我們不調用的話,后面的管道就終止了。
還有一點就是IApplicationBuilder會提供給我們一個Map,我們可以理解為路由的機制。
我們后面的路由也是在這個基礎上進行配置的。運行效果:
自己動手構建RequestDelegate管道
什么是RequestDelegate
ASP.NET Core的中間件通過一個類型Func<RequestDelegate, RequestDelegate>的委托對象來表示,而RequestDelegate也是一個委托,它代表一項請求處理任務。
每個中間件都承載着獨立的請求處理任務,它本質上也體現了在當前HttpContext下針對請求的處理操作,那么為什么中間件不直接通過一個RequestDelegate對象來表示,而是表示為一個類型為Func<RequestDelegate, RequestDelegate>的委托對象呢?原因很簡單,中間件並不孤立地存在,所有注冊的中間件最終會根據注冊的先后順序組成一個鏈表,每個中間件不僅僅需要完成各自的請求處理任務外,還需要驅動鏈表中的下一個中間件。
對於一個由多個Func<RequestDelegate, RequestDelegate>對象組成的中間鏈表來說,某個中間件會將后一個Func<RequestDelegate, RequestDelegate>對象的返回值作為輸入,而自身的返回值則作為前一個中間件的輸入。某個中間件執行之后返回的RequestDelegate對象不僅僅體現了自身對請求的處理操作,而是體現了包含自己和后續中間件一次對請求的處理。那么對於第一個中間件來說,它執行后返回的RequestDelegate對象實際上體現了整個應用對請求的處理邏輯。
模擬RequestDelegate
首先先用VSCode新建一個控制台項目:MyPipeline,然后打開
dotnet new console --name MyPipeline
新建一個Context.cs類
using System; using System.Threading.Tasks; namespace MyPipeline { public class Context { } }
新建一個RequestDelegate.cs類
using System; using System.Threading.Tasks; namespace MyPipeline { public delegate Task RequestDelegate(Context context); }
在Program.cs中聲明一個接收委托、返回委托的List,並初始化
public static List<Func<RequestDelegate,RequestDelegate>> _list=new List<Func<RequestDelegate,RequestDelegate>>();
//模擬ApplicationBuilder中的app.Use方法 public static void Use(Func<RequestDelegate,RequestDelegate> middleware) { _list.Add(middleware); }
在Main中調用
static void Main(string[] args) { //第一步 Use(next=>{ return context=>{ System.Console.WriteLine("1"); return next.Invoke(context); //return Task.CompletedTask; }; }); //第二步 Use(next=>{ return context=>{ System.Console.WriteLine("2"); return next.Invoke(context); }; }); RequestDelegate end=(context)=>{ System.Console.WriteLine("end..."); return Task.CompletedTask; }; _list.Reverse(); foreach(var middleware in _list) { end=middleware.Invoke(end); } //這時候我們沒有Context,所以直接new一個Context給它 end.Invoke(new Context()); Console.ReadLine(); }
結果:
這個時候我們在第一步進行終止操作:
結果: