初始化新的项目,在Configure的第一行可以看到如下代码:
if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); app.UseHsts(); }
代码使用 IsDevelopment() 判断了当前是否为开发者模式,然后通过 UseDeveloperExceptionPage() 就跳转到了堆栈错误页面。当然,正式环境的时候可不能这样,所以用 UseExceptionHandler() 这个默认错误处理方法,跳转到了错误提示页面, UseExceptionHandler() 还有一个重载方法使用 lambda 表达式来处理异常:
app.UseExceptionHandler(errorApp => { errorApp.Run(async context => { context.Response.StatusCode = 500; context.Response.ContentType = "text/html"; await context.Response.WriteAsync("<html lang="en"><body> "); await context.Response.WriteAsync("ERROR!<br><br> "); }); });
一、异常过滤器
创建我们自己的异常过滤器需要继承 IAsyncExceptionFilter ,然后实现 OnExceptionAsync 方法对错误信息进行处理:
public class MyCustomerExceptionFilter : IAsyncExceptionFilter { public Task OnExceptionAsync(ExceptionContext context) { if (context.ExceptionHandled == false) { string msg = context.Exception.Message; context.Result = new ContentResult { Content = msg, StatusCode = StatusCodes.Status200OK, ContentType = "text/html;charset=utf-8" }; } context.ExceptionHandled = true; //异常已处理了 return Task.CompletedTask; } }
这里将 context.ExceptionHandled 设置为了true,表示该异常已经被处理,后续的异常处理的中间件也不会再重复处理这个异常了。最后在 Startup.cs 中加入它就可以看:
services.AddControllers(options => options.Filters.Add(new MyCustomerExceptionFilter()));
二、异常中间件
异常中间件和异常过滤器的区别就是,异常中间件的范围更广,异常过滤器只能处理mvc中发生的错误,而中间件可以捕获其之后的所有异常。如下:
public class MyExceptionMiddleware { private readonly RequestDelegate _next; public MyExceptionMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext httpContext) { try { await _next(httpContext); } catch (Exception ex) { httpContext.Response.ContentType = "application/problem+json"; var title = "An error occured: " + ex.Message; var details = ex.ToString(); var problem = new ProblemDetails { Status = 200, Title = title, Detail = details }; //Serialize the problem details object to the Response as JSON (using System.Text.Json) var stream = httpContext.Response.Body; await JsonSerializer.SerializeAsync(stream, problem); } } }
app.UseMiddleware<MyExceptionMiddleware>();
不过这样也没啥必要,因为 UseExceptionHandler 的重载方法也可以实现,最开始的时候已经给出了。