在 ASP.NET Core 上有個好用的功能叫 Middleware,它可以在處理 request 時做一些介入,例如搜集 log 或是做錯誤處理,以下示範如何做錯誤處理並把錯誤記錄在 log 中。

首先,新增一個類別叫 ExceptionMiddleware,它大致上有以下基本格式:

public class ExceptionMiddleware
{
    private readonly RequestDelegate _next;

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

    public async Task Invoke(HttpContext context)
    {
        await _next(context);
    }
}

大致上,處理的邏輯會在Invoke這個 method 裡。然後在 Startup.cs 中加入以下程式碼:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    ...

    //setup middleware
    app.UseMiddleware<ExceptionMiddleware>();

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    ...
}

然後在 Program.cs 多呼叫一個 method UseNLog

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        }).UseNLog();

後面的程式碼,會用到 NLog,關於用法可參考下列文章:

完整的 Middleware 寫法如下:

public class ExceptionMiddleware
{
    private readonly RequestDelegate _next;
    private ILogger _logger = NLogBuilder.ConfigureNLog("nlog.config").GetLogger("MyLog");

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

    public async Task Invoke(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (Exception ex)
        {
            _logger.Error(ex, ex.Message);
            MyExceptionClass errorResponse = ExceptionHandling();
            errorResponse.message = $"{GetType().Name} catch exception. Message: {ex.Message}";
            
            string responseString = System.Text.Json.JsonSerializer.Serialize(errorResponse);
            _logger.Error(responseString);
            context.Response.StatusCode = StatusCodes.Status500InternalServerError;
            await context.Response
                .WriteAsync(responseString);
        }
    }

    private MyExceptionClass ExceptionHandling()
    {
        MyExceptionClass response = new MyExceptionClass
        {
            code = 500,
            createdTimeUtc = string.Format("{0:s}", DateTime.UtcNow)
        };
        return response;
    }
}

public class MyExceptionClass
{
    public string createdTimeUtc { get; set; }
    public int code { get; set; }
    public string message { get; set; }
}

參考資料