當API被呼叫且發生例外時,不太會希望預設的錯誤訊息被傳回給使用者,在C#中可以使用try catch攔截錯誤訊息。

但在每個可能會發生錯誤的地方都加上try catch相當繁瑣,使用Middleware可以捕捉錯誤訊息,並在返回給使用者之前統一處理,不僅可以節省開發時間,還能將錯誤訊息攔截,避免洩漏過多內部訊息給使用者,提高安全性。

環境

  • macOS Ventura 13.0(Apple M1 Pro)
  • .NET 6.0
  • Visual Studio Community 2022 for Mac 17.6.1

Middleware簡介

ASP.NET Core中定義的Middleware可以用來處理所有的HTTP Request和Response,他們會一個串著一個,像一個管線(Pipeline)。

每個Middleware可以決定是否要進入下一個Middleware,若沒有呼叫next()則不會進入下一個Middleware。

由於所有的請求都會經過所有的Middleware,想要在例外發生時有一個地方可以捕捉所有例外,Middleware再適合不過了。

實作Middleware

在專案中新增一個Middlewares資料夾,統一存放自定義的Middlewares。

接著在資料夾中新增檔名為ExceptionHandleMiddleware.cs的類別,在類別中加入下列程式碼:

public class ExceptionHandleMiddleware
{
    private readonly RequestDelegate _next;

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

    public async Task Invoke(HttpContext context)
    {
        try
        {
            //執行下一步
            await _next(context);
        }
        catch (Exception exception)
        {
            //當錯誤發生時呼叫 HandleExceptionAsync 方法,不執行下一個Middleware
            await HandleExceptionAsync(context, exception);
        }
    }

    //直接返回 InternalServerError 給使用者
    private static Task HandleExceptionAsync(HttpContext context, Exception exception)
    {
        context.Response.ContentType = "application/json";
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;

        return context.Response.WriteAsync($"{context.Response.StatusCode} Internal Server Error.");
    }
}

Middleware完成後依照Program.cs的形式將Middleware使用IApplicationBuilder包起來,在Middlewares資料夾中新增名稱為ExceptionHandleMiddlewareExtensions.cs的類別,檔案內容如下:

public static class ExceptionHandleMiddlewareExtensions
{
    public static IApplicationBuilder UseExceptionHandleMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<ExceptionHandleMiddleware>();
    }
}

接著在Program.cs中加入app.UseExceptionHandleMiddleware();即可完成自訂Middleware的設定。

public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        ...
            
        var app = builder.Build();

        ...

        app.UseExceptionHandleMiddleware();//加入這行即可完成設定

        ...

        app.Run();
    }
}
參考資料