上一章講了請求管道與中間件的基本概念和工作模式,也介紹了 ASP.NET Core 中內置的中間件,這一章介紹一下如何自定義中間件,這是很常用也很重要的內容,日常工作中很多場景我們都可以自定義自己的中間件,通過對請求管道進行攔截執行我們自己的業務邏輯,實現各種需求。這也是 ASP.NET Core ...
上一章講了請求管道與中間件的基本概念和工作模式,也介紹了 ASP.NET Core 中內置的中間件,這一章介紹一下如何自定義中間件,這是很常用也很重要的內容,日常工作中很多場景我們都可以自定義自己的中間件,通過對請求管道進行攔截執行我們自己的業務邏輯,實現各種需求。這也是 ASP.NET Core 框架下的一種最基本的 AOP 編程方式。
中間件本質上是一個委托,上一章的例子中我們將中間件的代碼邏輯通過Use()、Run()、Map() 等方法寫在了入口文件中,這樣很不優雅。我們可以對這些代碼進行封裝,最簡單的封裝方式,就是通過一個靜態類將相關的代碼寫成靜態方法,在 Use() 等方法中只需要傳入靜態方法即可。但是這種方法一樣不夠優雅,我們可以模仿微軟內置中間件和一些第三方組件提供的中間件的封裝方式。例如,靜態文件中間件的實現源碼:
其實對於中間件的封裝,可以不實現某個介面,但是它有一套約定的規則。
(1) 中間件類名必須是 XXXMiddleware 格式
(2) 中間件類中必須有 public Task Invoke(HttpContext context) 方法
所以對於上面例子中的代碼,我們可以進行以下的優化
namespace MiddlewareSample.Middlewares
{
public class HelloMiddleware
{
private readonly RequestDelegate _next;
// 註入相應的依賴,這裡是下一個中間件的委托,如果有其他依賴項需要用到,也可以從構造函數註入
public HelloMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
await context.Response.WriteAsync("Hello Middlerware1 ! ");
if (context.Request.Query.TryGetValue("query", out var query))
{
await context.Response.WriteAsync(query);
}
// 調用下一個中間件
await _next(context);
await context.Response.WriteAsync("End Middleware1 ! ");
}
}
}
之後再提供一個擴展方法,以供使用者便捷地進行註冊使用。
using MiddlewareSample.Middlewares;
namespace Microsoft.AspNetCore.Builder
{
public static class HelloExtensions
{
public static IApplicationBuilder UseHello(this IApplicationBuilder app)
{
if(app == null)
{
throw new ArgumentNullException(nameof(app));
}
// 中間件的註冊方式
app.UseMiddleware<HelloMiddleware>();
return app;
}
}
}
這裡使用了另一種中間件的註入方式,通過查看源碼,可以看到最終也是調用了 Use() 方法進行註冊的。在這個過程中,會通過反射等手段通過我們封裝好的中間件類生成一個委托。
之後就是配置使用了,在 入口文件中將原本的 Use() 方法替換成擴展方法。
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseHello();
app.Run(async context =>
{
await context.Response.WriteAsync("Hello last Middleware ! ");
});
app.Run();
最終的執行結果是一樣的。
ASP.NET Core 系列:
目錄:ASP.NET Core 系列總結
上一篇:ASP.NET Core - 請求管道與中間件