.net core 5.0 之自定義中介軟體
微軟官方自定義中介軟體文件:https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/write?view=aspnetcore-5.0#per-request-middleware-dependencies
1. 中介軟體的定義:(官方文件) https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/?view=aspnetcore-5.0
中介軟體是一種裝配到應用管道以處理請求和響應的軟體。 每個元件:
a. 選擇是否將請求傳遞到管道中的下一個元件。
b. 可在管道中的下一個元件前後執行工作。
請求委託用於生成請求管道。 請求委託處理每個 HTTP 請求。
使用 RunMap 和 Use 擴充套件方法來配置請求委託。 可將一個單獨的請求委託並行指定為匿名方法(稱為並行中介軟體),或在可重用的類中對其進行定義。 這些可重用的類和並行匿名方法即為中介軟體,也叫中介軟體元件。 請求管道中的每個中介軟體元件負責呼叫管道中的下一個元件,或使管道短路。 當中間件短路時,它被稱為“終端中介軟體”,因為它阻止中介軟體進一步處理請求。
2. 管道中介軟體官方建議的執行順序
3. 自定義中介軟體實現必須滿足兩點條件
3.1. 具有型別為 RequestDelegate 的引數的公共建構函式。
3.2. 名為 Invoke
或 InvokeAsync
的公共方法。 此方法必須:
a. 返回 Task
。
b. 接受型別 HttpContext 的第一個引數。
4. 實現示例
public class CustomMiddleware { public string _msg; public RequestDelegate _requestDelegate; public CustomMiddleware(RequestDelegate requestDelegate, string msg) { _requestDelegate = requestDelegate; _msg = msg; } public async Task InvokeAsync(HttpContext httpContext) { Console.WriteLine(_msg); await _requestDelegate(httpContext); } }
public static class MiddlewareExtension { public static IApplicationBuilder Custom(this IApplicationBuilder app,string msg) { return app.UseMiddleware<CustomMiddleware>(msg); } }
app.Custom("hello");
請求http://localhost:5000/之後的執行結果:
5. 擴充套件資料:
.net core 都是通過 IApplicationBuilder 來新增中介軟體建立管道,所以中介軟體都是圍繞它來建立的。請求管道包含一系列請求委託,依次呼叫。每個委託均可在下一個委託前後執行操作。 應儘早在管道中呼叫異常處理委託,這樣它們就能捕獲在管道的後期階段發生的異常。
配置請求委託的幾種方式:
-
app.Use(): 將多個請求委託連結在一起,按照順序依次執行。
next
引數表示管道中的下一個委託。 可通過不呼叫 next 引數使管道短路。 通常可在下一個委託前後執行操作.
public class Startup { public void Configure(IApplicationBuilder app) { app.Use(async (context, next) => { // Do work that doesn't write to the Response. await next.Invoke(); // Do logging or other work that doesn't write to the Response. }); app.Run(async context => { await context.Response.WriteAsync("Hello from 2nd delegate."); }); } }
- app.Run():委託不會收到
next
引數。 第一個Run
委託始終為終端,用於終止管道。如果在Run
委託之後添加了另一個Use
或Run
委託,則不會呼叫該委託。
public class Startup { public void Configure(IApplicationBuilder app) { app.Run(async context => { await context.Response.WriteAsync("Hello from 2nd delegate."); }); } }
- app.map() : 用作約定來建立管道分支。
Map
基於給定請求路徑的匹配項來建立請求管道分支。 如果請求路徑以給定路徑開頭,則執行分支。
public class Startup { private static void HandleMapTest1(IApplicationBuilder app) { app.Run(async context => { await context.Response.WriteAsync("Map Test 1"); }); } private static void HandleMapTest2(IApplicationBuilder app) { app.Run(async context => { await context.Response.WriteAsync("Map Test 2"); }); } public void Configure(IApplicationBuilder app) { app.Map("/map1", HandleMapTest1); app.Map("/map2", HandleMapTest2); app.Run(async context => { await context.Response.WriteAsync("Hello from non-Map delegate. <p>"); }); } }
下表使用前面的程式碼顯示來自 http://localhost:1234
的請求和響應。
-
app.MapWhen() : 基於給定前面的謂詞的結果來建立請求管道分支。
MapWhen(this IApplicationBuilder app, Func<HttpContext, bool> predicate, Action<IApplicationBuilder> configuration)簡單來說就是predicate如果為true則執行後面的configuration委託
-
app.UseWhen() : 也基於給定謂詞的結果建立請求管道分支。 與
MapWhen
不同的是,如果這個分支不發生短路或包含終端中介軟體,則會重新加入主管道。