.NET(Core) WebAPI 使用 Custom Middleware PipeLine

以往,在.NET Framework時代,有Message Handller的方式,可以透過PipeLine,逐層處理Request與Response
現在,走進.NET(Core)的WebAPI,找到類似的機制,但目前討論的不多,所以做個紀錄

緣起

以往,在.NET Framework時代,有Message Handler的方式,可以透過PipeLine,逐層處理Request與Response
現在,走進.NET(Core)的WebAPI,找到類似的機制,但目前討論的不多,所以做個紀錄。

回顧Message Handler

過往,我們會透過Message Handler,在Client的Request還沒進入Controller之前,把一些放在Header中的東西,預先處理(驗證、轉換、後製、...),然後將處理後的資訊,補充在Header中,繼續往下傳。或者在Response的過程中,一些共同要處理的,也可以在Message Handler中層層處理過後,再持續往外傳。這樣的機制小喵覺得還蠻好用的,每一層的任務也可以單一單純。
 

Custom Middleware

現在小喵終於有機會要轉到.NET開始了,之前好用的 Message Handler就要找替代方案,幾經尋找(感謝AI的幫忙),終於找到類似的機制,這就是這一篇的主題【Custom Middlerware】。
一樣會有PipeLine的運作,一樣可以處理Request與Response非同步的處理。而這部分,其實官方的範本已經寫得很不錯,請參考:

撰寫自訂的 ASP.NET Core 中介軟體
https://learn.microsoft.com/zh-tw/aspnet/core/fundamentals/middleware/write?view=aspnetcore-8.0

小喵的需求,是希望在Header中,加上一個ApiToken的資料作為驗證機制,這個ApiToken,呼叫端與我這邊,會有共同的邏輯,每隔一段時間會切換,用以鎖定只有合法ApiToken的Request才能合法繼續進入,否則就退回
相關的範例如下:

建立Custom Middleware類別
using System.Globalization;

namespace PTCMAPI.Models.MWs
{
    public class RequestApiTokenMiddleware
    {
        private readonly RequestDelegate _next;

        public RequestApiTokenMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task Invoke(HttpContext context)
        {
            if (context.Request.Headers.TryGetValue("ApiToken", out var apiToken))
            {
                // Validate the API token
                if (!IsValidApiToken(apiToken))
                {
                    context.Response.StatusCode = StatusCodes.Status401Unauthorized;
                    await context.Response.WriteAsync("ApiToken不正確");
                    return;
                }
            }
            else
            {
                context.Response.StatusCode = StatusCodes.Status400BadRequest;
                await context.Response.WriteAsync("無法取得ApiToken");
                return;
            }

            await _next(context);
        }

        private bool IsValidApiToken(string apiToken)
        {
            // 驗證ApiToken邏輯在此,請自行修改合適的邏輯,這邊以固定的內容作示範
            return apiToken == "9F7BD0138AF743E3980A8FFACD38F8C7";
        }
    }

    public static class RequestApiTokenMiddlewareExtensions
    {
        public static IApplicationBuilder UseRequestApiToken(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<RequestApiTokenMiddleware>();
        }
    }
}
在Program.cs中使用

在適當的位置,加入以下這句

app.UseRequestApiToken();

這樣,就處理好一層的Custom Middleware

 

同場加映:在Swagger中增加輸入ApiToken

.NET 8的WebAPI專案建立過程中,可以順便加上Swagger,來提供WebAPI的說明與測試。既然已經在WebAPI加上ApiToken的驗證,那麼在Swagger中,也應該加上一個ApiToken的輸入,讓在Swagger測試時,也可以隨時輸入該ApiToken,以利測試。相關作法如下:

步驟一:新增Swagger要用的AddCustomHeaderParameter類別

小喵在Models中的Swagger資料夾中,新增一個類別,命名為 AddCustomHeaderParameter

using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace PTCMAPI.Models.Swagger
{
    public class AddCustomHeaderParameter : IOperationFilter
    {
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            if (operation.Parameters == null)
            {
                operation.Parameters = new List<OpenApiParameter>();
            }

            operation.Parameters.Add(new OpenApiParameter
            {
                Name = "ApiToken",
                In = ParameterLocation.Header,
                Required = true,
                Schema = new OpenApiSchema
                {
                    Type = "string"
                }
            });
        }
    }
}
步驟二:修改Program.cs

將 Program.cs 中,原本的 builder.Services.AddSwaggerGen(); 改為以下:

builder.Services.AddSwaggerGen(options =>
{
    options.OperationFilter<AddCustomHeaderParameter>();
});

就醬子,Swagger中,輸入ApiToken的部分也做好了。

末記

從.NET Framework 轉換到 .NET的世界,有些東西還是陌生的,以往覺得好的東西,一點一滴地慢慢找回可以對應的機制,這次使用Custom Middleware來取代之前的Message Handler。提供改有需要的人參考,也順便紀錄一下,以免記性不好忘了。

 


以下是簽名:


Microsoft MVP
Visual Studio and Development Technologies
(2005~2019/6) 
topcat
Blog:http://www.dotblogs.com.tw/topcat