ASP.NET Core - 自定義中介軟體

啊晚發表於2023-02-18

上一章講了請求管道與中介軟體的基本概念和工作模式,也介紹了 ASP.NET Core 中內建的中介軟體,這一章介紹一下如何自定義中介軟體,這是很常用也很重要的內容,日常工作中很多場景我們都可以自定義自己的中介軟體,透過對請求管道進行攔截執行我們自己的業務邏輯,實現各種需求。這也是 ASP.NET Core 框架下的一種最基本的 AOP 程式設計方式。

中介軟體本質上是一個委託,上一章的例子中我們將中介軟體的程式碼邏輯透過Use()、Run()、Map() 等方法寫在了入口檔案中,這樣很不優雅。我們可以對這些程式碼進行封裝,最簡單的封裝方式,就是透過一個靜態類將相關的程式碼寫成靜態方法,在 Use() 等方法中只需要傳入靜態方法即可。但是這種方法一樣不夠優雅,我們可以模仿微軟內建中介軟體和一些第三方元件提供的中介軟體的封裝方式。例如,靜態檔案中介軟體的實現原始碼:

image

其實對於中介軟體的封裝,可以不實現某個介面,但是它有一套約定的規則。
(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() 方法進行註冊的。在這個過程中,會透過反射等手段透過我們封裝好的中介軟體類生成一個委託。

image

之後就是配置使用了,在 入口檔案中將原本的 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();

最終的執行結果是一樣的。

image



ASP.NET Core 系列:
目錄:ASP.NET Core 系列總結
上一篇:ASP.NET Core - 請求管道與中介軟體

相關文章