前言
在程式設計中,我們會遇到各種各樣的例外問題,一個好的例外處理解決方案能夠幫助開發者快速的定位問題,也能夠給用戶更好的用戶體驗,
例外處理的幾種方式
1、通過例外過濾器捕獲例外進行處理
2、自定義例外處理中間件
在這里我選擇自定義例外處理中間件,中間件依托于請求管道運行,并且中間件的執行是有序的,與業務隔離開的,將中間件放置在請求管道開始能夠捕獲到全域例外,
例外中間件定義
我們先新建一個類來保存結果資訊
public abstract class AjaxResponseBase
{
public string TargetUrl { get; set; }
public bool Success { get; set; }
public ErrorInfo Error { get; set; }
public bool UnAuthorizedRequest { get; set; }
public string StatusCode { get; set; }
}
中間件的定義
public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;
public ExceptionMiddleware(RequestDelegate next
, ILoggerFactory loggerFactory
{
_next = next;
_logger = loggerFactory.CreateLogger<ExceptionMiddleware>();
}
public async Task Invoke(HttpContext context)
{
ExceptionDispatchInfo edi;
try
{
var task = _next(context)
//判斷后續中間件處理是否成功完成,沒有的話捕獲例外
if (!task.IsCompletedSuccessfully)
{
//記錄例外資訊
await Awaited(context, () => task);
}
return;
}
catch (Exception ex)
{
edi = ExceptionDispatchInfo.Capture(ex);
}
//注意我們這里并沒有拋出例外,
await HandlerException(context, edi);
}
private async Task HandlerException(HttpContext context, ExceptionDispatchInfo edi)
{
if (context.Response.HasStarted)
{
// 回應開始拋出例外終止回應
edi.Throw();
}
//記錄例外資訊并將例外資訊寫入回應體中
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
var requestPath = context.Request.Path;
var exception = edi.SourceException;
var logMsg = $"SourseRoute {requestPath} {exception.Source} {exception.Message} {exception.StackTrace} ";
_logger.LogError(logMsg);
AjaxResponse response = new AjaxResponse();
response.Success = false;
response.StatusCode = "500";
ErrorInfo error = new ErrorInfo();
response.Error = error;
error.Error = logMsg;
await context.Response.WriteAsJsonAsync(response);
}
//捕獲后續管道的例外
private async Task Awaited(HttpContext context, Func<Task> func)
{
ExceptionDispatchInfo? edi = null;
try
{
await func.Invoke();
}
catch (Exception exception)
{
edi = ExceptionDispatchInfo.Capture(exception);
}
if (edi != null)
{
await HandlerException(context, edi);
}
}
}
使用
注意請將中間件放置在請求管道的開始處,這樣才能捕獲到全域的例外并且記錄下了
app.UseMiddleware<ExceptionMiddleware>();
在控制器中拋出例外
可以看到我們在swagger請求控制器時已經記錄了例外資訊并且列印了出來
中間件與例外過濾器的比較
二者都可以用來捕獲程式的例外,只是捕獲例外的范圍不一樣,IExceptionFilter 作為過濾器的一種,它只能捕獲控制器內部的例外,如果我們的例外發生控制器之外就無法捕獲了,將例外中間件放置在請求管道的第一個,可以捕獲到全域的例外,
最后,如有不足,請多指教
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/548102.html
標籤:.NET技术
下一篇:WPF 入門基礎