ASP.NET Core Web APIexception处理
在使用常规ASP.NET Web API多年后,我开始使用ASP.NET Core作为新的REST API项目。 我没有看到在ASP.NET Core Web API中处理exception的好方法。 我试图实现exception处理filter/属性:
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 }; } }
这里是我的启动filter注册:
services.AddMvc(options => { options.Filters.Add(new AuthorizationFilter()); options.Filters.Add(new ErrorHandlingFilter()); });
我遇到的问题是,当我的AuthorizationFilter
exception发生时,它不是由ErrorHandlingFilter
处理。 我期待它被捕获,就像它使用旧的ASP.NET Web API。
那么如何捕获所有的应用程序exception以及Action Filters的exception呢?
exception处理中间件
经过多次不同的exception处理方法的实验后,我最终使用了中间件。 它最适合我的ASP.NET Core Web API应用程序。 它处理应用程序exception以及filter的exception。 这是我的exception处理中间件:
public class ErrorHandlingMiddleware { private readonly RequestDelegate next; public ErrorHandlingMiddleware(RequestDelegate next) { this.next = next; } public async Task Invoke(HttpContext context /* other scoped dependencies */) { try { await next(context); } catch (Exception ex) { await HandleExceptionAsync(context, ex); } } private static Task HandleExceptionAsync(HttpContext context, Exception exception) { var code = HttpStatusCode.InternalServerError; // 500 if unexpected if (exception is MyNotFoundException) code = HttpStatusCode.NotFound; else if (exception is MyUnauthorizedException) code = HttpStatusCode.Unauthorized; else if (exception is MyException) code = HttpStatusCode.BadRequest; var result = JsonConvert.SerializeObject(new { error = exception.Message }); context.Response.ContentType = "application/json"; context.Response.StatusCode = (int)code; return context.Response.WriteAsync(result); } }
在Startup
类中的MVC之前注册它:
app.UseMiddleware(typeof(ErrorHandlingMiddleware)); app.UseMvc();
这是一个exception响应的例子:
{ "error": "Authentication token is not valid." }
你可以添加堆栈跟踪,exceptiontypes名称,错误代码或任何你想要的。 非常灵活。 希望这是你的一个很好的起点!
你最好的select是使用中间件来实现你正在寻找的日志。 你想把你的exception日志logging在一个中间件中,然后在不同的中间件中处理显示给用户的错误页面。 这允许逻辑的分离,并遵循微软用2个中间件组件devise的devise。 这是一个很好的链接到微软的文档: ASP.Net核心error handling
对于您的具体示例,您可能需要使用StatusCodePage中间件中的某个扩展或像这样推出自己的扩展。
你可以在这里find一个例子: ExceptionHandlerMiddleware.cs
public void Configure(IApplicationBuilder app) { // app.UseErrorPage(ErrorPageOptions.ShowAll); // app.UseStatusCodePages(); // app.UseStatusCodePages(context => context.HttpContext.Response.SendAsync("Handler, status code: " + context.HttpContext.Response.StatusCode, "text/plain")); // app.UseStatusCodePages("text/plain", "Response, status code: {0}"); // app.UseStatusCodePagesWithRedirects("~/errors/{0}"); // app.UseStatusCodePagesWithRedirects("/base/errors/{0}"); // app.UseStatusCodePages(builder => builder.UseWelcomePage()); app.UseStatusCodePagesWithReExecute("/Errors/{0}"); // I use this version // Exception handling logging below app.UseExceptionHandler(); }
如果你不喜欢那个具体的实现,那么你也可以使用ELM中间件 ,下面是一些例子: Elm Exception Middleware
public void Configure(IApplicationBuilder app) { app.UseStatusCodePagesWithReExecute("/Errors/{0}"); // Exception handling logging below app.UseElmCapture(); app.UseElmPage(); }
如果这不能满足您的需求,那么您可以通过查看ExceptionHandlerMiddleware和ElmMiddleware的实现来掌握构build您自己的中间件组件的概念。
在StatusCodePages中间件下方添加exception处理中间件非常重要,但最重要的是您的其他中间件组件。 这样,你的exception中间件将捕获exception,logging它,然后允许请求进行到StatusCodePage中间件,该中间件将向用户显示友好的错误页面。