异常是应用程序中发生的运行时错误。 如果处理不当,将终止正在运行的程序。 我们如何防止这种情况发生? 我们可以使用全局异常处理程序来确保捕获所有未处理的异常。
为了在ASP.Net Core Web API中实现全局异常处理,我们可以利用内置的中间件UseExceptionHandler。 中间件是插入到请求处理管道中的软件组件,用于处理请求和响应。
在构建ASP.Net Core应用程序时,我们可以利用各种中间件组件来自定义请求和响应的处理,甚至检查,路由或修改流经管道的请求和响应消息。
在本文中,我将展示如何使用UseExceptionHandler中间件在ASP.Net Core Web API中全局处理异常。
在Visual Studio 2017中创建ASP.Net Core Web API项目
首先,让我们创建一个ASP.Net Core Web API项目。 如果您的系统已启动并运行Visual Studio 2017,请按照下面概述的步骤创建一个ASP.Net Core Web API项目。
- 启动Visual Studio 2017 IDE。
- 单击文件>新建>项目。
- 从显示的模板列表中选择“ ASP.Net Core Web应用程序(.Net Core)”。
- 指定项目的名称。
- 单击确定保存项目。
- 选择“ .Net Core”作为运行时,然后从窗口顶部的下拉列表中选择ASP.Net Core 2.1(或更高版本)。
- 选择“ API”作为项目模板。
- 确保未选中“启用Docker支持”和“配置HTTPS”复选框。 我们将不会使用这些功能。
- 确保选择“无身份验证”,因为我们也不会使用身份验证。
- 单击确定。
这将创建一个新的ASP.Net Core Web API项目。 在以下各节中,我们将使用该项目来实现全局异常处理。
在ASP.Net Core中使用UseExceptionHandler中间件
ASP.Net Core请求处理管道包括一系列中间件组件。 该管道反过来包含一系列的请求委托,它们被一个又一个地调用。 当传入的请求流经管道中的每个中间件组件时,这些组件中的每一个都可以处理请求,也可以将请求传递给管道中的下一个组件。
以下代码段说明了如何配置UseExceptionHandler中间件,以在发生异常时将用户重定向到错误页面。
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseExceptionHandler("/Home/Error");
app.UseMvc();
}
如果您想捕获异常对象的详细信息(例如,堆栈跟踪等),则可以使用以下代码。
app.UseExceptionHandler(
options =>
{
options.Run(
async context =>
{
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.ContentType = "text/html";
var exceptionObject = context.Features.Get<IExceptionHandlerFeature>();
if (null != exceptionObject)
{
var errorMessage = $"<b>Error: {exceptionObject.Error.Message}</b>{exceptionObject.Error.StackTrace}";
await context.Response.WriteAsync(errorMessage).ConfigureAwait(false);
}
});
}
);
接下来,使用以下代码更新ValuesController中的默认Get操作方法。
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
throw new Exception("An error occurred...");
}
运行该应用程序,您将看到在Web浏览器中显示的堆栈跟踪,如下图所示。
创建一个自定义中间件来处理ASP.Net Core Web API中的异常
您还可以编写自己的中间件来处理异常。 这是一个示例,说明了典型的自定义中间件类。 编写自己的自定义中间件来处理异常可以提供更大的灵活性。 您可以添加堆栈跟踪,异常类型名称,错误代码或其他任何您想包含在错误消息中的内容。
这是一个示例,说明了典型的自定义中间件类。
public class CustomExceptionMiddleware
{
private readonly RequestDelegate _next;
public CustomExceptionMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next.Invoke(context);
}
catch (Exception ex)
{
//Write code to handle exception here
}
}
}
请注意,请求委托将传递给任何中间件。 然后,中间件要么对其进行处理,要么将其传递给链中的下一个中间件。 如果请求失败,则将引发异常,并在catch块中调用HandleExceptionAsync方法。
现在,使用以下代码更新Invoke方法。
public async Task Invoke(HttpContext context)
{
try
{
await _next.Invoke(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context,
ex).ConfigureAwait(false);
}
}
这是HandleExceptionAsync方法的代码。
private static Task HandleExceptionAsync(HttpContext context, Exception exception)
{
context.Response.ContentType = "application/json";
int statusCode = (int)HttpStatusCode.InternalServerError;
var result = JsonConvert.SerializeObject(new {StatusCode = statusCode, ErrorMessage = exception.Message });
context.Response.ContentType = "application/json";
context.Response.StatusCode = statusCode;
return context.Response.WriteAsync(result);
}
这是CustomExceptionMiddleware类的完整代码清单,供您参考。
public class CustomExceptionMiddleware
{
private readonly RequestDelegate _next;
public CustomExceptionMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next.Invoke(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex).ConfigureAwait(false);
}
}
private static Task HandleExceptionAsync(HttpContext context, Exception exception)
{
context.Response.ContentType = "application/json";
int statusCode = (int)HttpStatusCode.InternalServerError;
var result = JsonConvert.SerializeObject(new {StatusCode = statusCode,
ErrorMessage = exception.Message });
context.Response.ContentType = "application/json";
context.Response.StatusCode = statusCode;
return context.Response.WriteAsync(result);
}
}
仅需两个步骤。 接下来,创建一个名为ExceptionMiddlewareExtensions的静态类,并包含以下代码。
public static class ExceptionMiddlewareExtensions
{
public static void UseCustomExceptionMiddleware(this IApplicationBuilder app)
{
app.UseMiddleware<CustomExceptionMiddleware>();
}
}
最后,您现在可以在Startup类的Configure方法中打开自定义中间件,如下面的代码片段所示。
public void Configure(IApplicationBuilder app,
IHostingEnvironment env)
{
app.UseCustomExceptionMiddleware();
app.UseMvc();
}
运行应用程序时,异常输出将显示在Web浏览器中,如下图所示。
在每个应用程序中,异常处理都是一个贯穿各领域的问题。 幸运的是,我们可以利用ASP.Net Core中的全局异常处理来确保捕获到每个异常,并且无需在每次编写新的控制器或控制器方法时都编写额外的样板代码。 使用全局异常处理,我们只需要在一个地方一次为我们的应用编写异常处理代码。 最好编写自己的自定义中间件来全局处理异常。