ASP.NET Core 全局異常處理

IAsyncExceptionFilter

在 ASP.NET Core 中,可以使用異常過濾器(Exception Filter)來捕獲和處理應用程序中的異常。IExceptionFilter 接口和 IAsyncExceptionFilter 接口都可以用來實現自定義的異常過濾器。不過我更建議您考慮它的異步版本:IAsyncExceptionFilter。

public class CustomExceptionFilter : IAsyncExceptionFilter
{
    private readonly ILogger<CustomExceptionFilter> _logger;

    public CustomExceptionFilter(ILogger<CustomExceptionFilter> logger)
    {
        _logger = logger;
    }

    public async Task OnExceptionAsync(ExceptionContext context)
    {
        _logger.LogError(context.Exception, "An error occurred.");

        if (!context.ExceptionHandled)
        {
            context.Result = new ViewResult { ViewName = "Error" };
            context.ExceptionHandled = true;
        }

        await Task.CompletedTask;
    }
}

在這個示例中,我們創建了一個名爲 CustomExceptionFilter 的自定義異常過濾器,它實現了 IAsyncExceptionFilter 接口。在 OnExceptionAsync 方法中,我們記錄了異常並返回一個 ViewResult 對象來顯示用戶友好的錯誤信息。

要使用這個過濾器,只需要在 Startup.ConfigureServices 方法中註冊它:

services.AddMvc(options =>
{
    options.Filters.Add<CustomExceptionFilter>();
});

中間件處理異常

新建一箇中間件在管道中實現全局異常捕獲。

public class MyExceptionMiddleware
{
	private readonly RequestDelegate _next;
	private readonly ILogger<MyExceptionMiddleware> _logger;

	public MyExceptionMiddleware(RequestDelegate next, ILogger<MyExceptionMiddleware> logger)
	{
		_next = next;
		_logger = logger;
	}

	public async Task Invoke(HttpContext context)
	{
		try
		{
			await _next(context);
		}
		catch (Exception ex)
		{
			_logger.LogError($"An exception occurred: {ex}");

			context.Response.ContentType = "application/json";
			context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

			var jsonResponse = System.Text.Json.JsonSerializer.Serialize(new { error = ex.Message });
			await context.Response.WriteAsync(jsonResponse);
		}
	}
}

然後在 Startup.cs 中,註冊管道:

app.UseMiddleware<MyExceptionMiddleware>();

默認的AspNet Core異常處理

if (env.IsDevelopment())
{
	// dev環境,一旦報錯就會跳轉到錯誤堆棧頁面
	app.UseDeveloperExceptionPage();
	app.UseSwagger();
	app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "DaXiong.Demo.WebApi v1"));
}
else
{
	// 非dev環境輸出格式,個人根據實際情況擴展
	app.UseExceptionHandler(errorApp =>
	{
		errorApp.Run(async context =>
		{
			Console.WriteLine();
			// 處理異常並生成響應
			var exception = context.Features.Get<IExceptionHandlerPathFeature>().Error;
			var statusCode = (int)HttpStatusCode.InternalServerError;
			var message = "An error occurred while processing your request.";

			// 根據異常類型決定如何響應請求...

			// 生成響應
			context.Response.StatusCode = statusCode;
			context.Response.ContentType = "application/json";
			await context.Response.WriteAsync(JsonConvert.SerializeObject(new
			{
				statusCode,
				message
			}));
		});
	});
}

注意中間件的運行順序

image
後添加的中間件返回數據會覆蓋,前面的
image

一般情況使用默認的錯誤處理中間件也夠了

image

有了異常中間件還需要異常過濾器(IExceptionFilter )嗎

IExceptionFilter 作爲MVC中間件之間的內容,它需要MVC在發現錯誤之後將錯誤信息提交給它處理,因此它的錯誤處理範圍僅限於MVC中間件。所以,假如我們需要捕獲MVC中間件之前的一些錯誤,其實是捕獲不到的。 而對於ExceptionHandlerMiddleware中間件來說就很簡單了,它作爲第一個中間件,凡是在它之後的所有錯誤它都能夠捕獲得到。
但是,如果你想要在一個控制器或動作方法上執行特定的異常處理邏輯,仍然可以使用 IAsyncExceptionFilter。通過使用該接口,你可以在控制器或動作方法級別組織、記錄和響應異常。在這種情況下,控制器或動作方法將優先於全局的 UseExceptionHandler 中間件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章