在使用常规ASP.NET Web API多年之后,我将ASP.NET Core用于我的新REST API项目。我看不到任何在ASP.NET Core Web API中处理异常的好方法。我试图实现异常处理过滤器/属性:
public class ErrorHandlingFilter : ExceptionFilterAttribute { public override void OnException(ExceptionContext context) { HandleExceptionAsync(context); context.ExceptionHandled = true; } private static void HandleExceptionAsync(ExceptionContext context) { var exception = context.Exception; if (exception is MyNotFoundException) SetExceptionResult(context, exception, HttpStatusCode.NotFound); else if (exception is MyUnauthorizedException) SetExceptionResult(context, exception, HttpStatusCode.Unauthorized); else if (exception is MyException) SetExceptionResult(context, exception, HttpStatusCode.BadRequest); else SetExceptionResult(context, exception, HttpStatusCode.InternalServerError); } private static void SetExceptionResult( ExceptionContext context, Exception exception, HttpStatusCode code) { context.Result = new JsonResult(new ApiResponse(exception)) { StatusCode = (int)code }; } }
这是我的启动过滤器注册:
services.AddMvc(options => { options.Filters.Add(new AuthorizationFilter()); options.Filters.Add(new ErrorHandlingFilter()); });
我遇到的问题是,当发生异常时,AuthorizationFilter它不会由处理ErrorHandlingFilter。我期望它会像在旧的ASP.NET Web API中一样被捕获。
AuthorizationFilter
ErrorHandlingFilter
那么,如何捕获所有应用程序异常以及动作过滤器中的任何异常?
在使用不同的异常处理方法进行了许多实验之后,我最终使用了中间件。对于我的ASP.NET Core Web API应用程序,它表现得最好。它可以处理应用程序异常以及动作过滤器中的异常,并且我可以完全控制异常处理和HTTP响应。这是我的异常处理中间件:
public class ErrorHandlingMiddleware { private readonly RequestDelegate next; public ErrorHandlingMiddleware(RequestDelegate next) { this.next = next; } public async Task Invoke(HttpContext context /* other dependencies */) { try { await next(context); } catch (Exception ex) { await HandleExceptionAsync(context, ex); } } private static Task HandleExceptionAsync(HttpContext context, Exception ex) { var code = HttpStatusCode.InternalServerError; // 500 if unexpected if (ex is MyNotFoundException) code = HttpStatusCode.NotFound; else if (ex is MyUnauthorizedException) code = HttpStatusCode.Unauthorized; else if (ex is MyException) code = HttpStatusCode.BadRequest; var result = JsonConvert.SerializeObject(new { error = ex.Message }); context.Response.ContentType = "application/json"; context.Response.StatusCode = (int)code; return context.Response.WriteAsync(result); } }
在课堂上 在MVC之前 注册Startup:
Startup
app.UseMiddleware(typeof(ErrorHandlingMiddleware)); app.UseMvc();
您可以添加堆栈跟踪,异常类型名称,错误代码或您想要的任何内容。非常灵活。这是异常响应的示例:
{ "error": "Authentication token is not valid." }
考虑序列化响应对象以利用ASP.NET MVC的序列化设置在所有端点之间实现更好的序列化一致性时,考虑注入IOptions<MvcJsonOptions>该Invoke方法,然后使用该方法JsonConvert.SerializeObject(errorObj, opts.Value.SerializerSettings)。
IOptions<MvcJsonOptions>
Invoke
JsonConvert.SerializeObject(errorObj, opts.Value.SerializerSettings)
UseExceptionHandler对于简单的方案,还有另一个非显而易见的API 可以正常工作:
UseExceptionHandler
app.UseExceptionHandler(a => a.Run(async context => { var feature = context.Features.Get<IExceptionHandlerPathFeature>(); var exception = feature.Error; var result = JsonConvert.SerializeObject(new { error = exception.Message }); context.Response.ContentType = "application/json"; await context.Response.WriteAsync(result); }));
这不是设置异常处理的非常明显但简单的方法。但是,我仍然更喜欢中间件方法,因为我获得了更多控制权并具有注入必要依赖项的能力。