- A+
所属分类:.NET技术
前言
在程序设计中,我们会遇到各种各样的异常问题,一个好的异常处理解决方案能够帮助开发者快速的定位问题,也能够给用户更好的用户体验。
异常处理的几种方式
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 作为过滤器的一种,它只能捕获控制器内部的异常,如果我们的异常发生控制器之外就无法捕获了,将异常中间件放置在请求管道的第一个,可以捕获到全局的异常。
最后,如有不足,请多指教