今天,我想向您_展示一种处理_ ASP.NET Core 8 中异常_的新旧方法_。
在 ASP.NET Core 中实现异常处理的标准是使用中间件。中间件允许您在执行 HTTP 请求之前或之后引入逻辑。您可以轻松地扩展它以实现异常处理。在中间件中添加语句并返回错误 HTTP 响应。try-catch
有 3 种方法可以在 ASP.NET Core 中创建中间件:
基于约定的方法要求您定义一个方法。InvokeAsync
以下是约定下的定义:ExceptionHandlingMiddleware
public class ExceptionHandlingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<ExceptionHandlingMiddleware> _logger;
public ExceptionHandlingMiddleware(
RequestDelegate next,
ILogger<ExceptionHandlingMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception exception)
{
_logger.LogError(
exception, "Exception occurred: {Message}", exception.Message);
var problemDetails = new ProblemDetails
{
Status = StatusCodes.Status500InternalServerError,
Title = "Server Error"
};
context.Response.StatusCode =
StatusCodes.Status500InternalServerError;
await context.Response.WriteAsJsonAsync(problemDetails);
}
}
}
将捕获任何未处理的异常并返回问题详细信息响应。您可以决定要向呼叫者返回多少信息。在此示例中,我隐藏了异常详细信息。ExceptionHandlingMiddleware
还需要将此中间件添加到 ASP.NET Core 请求管道:
app.UseMiddleware<ExceptionHandlingMiddleware>();
ASP.NET Core 8 引入了用于管理异常的新抽象。内置的异常处理程序中间件使用实现来处理异常。IExceptionHandlerIExceptionHandler
此接口只有一种方法。TryHandleAsync
TryHandleAsync尝试处理 ASP.NET Core 管道中的指定异常。如果可以处理异常,则应返回 .如果无法处理异常,则应返回 。这允许您为不同的方案实现自定义异常处理逻辑。truefalse
下面是一个实现:GlobalExceptionHandler
internal sealed class GlobalExceptionHandler : IExceptionHandler
{
private readonly ILogger<GlobalExceptionHandler> _logger;
public GlobalExceptionHandler(ILogger<GlobalExceptionHandler> logger)
{
_logger = logger;
}
public async ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
CancellationToken cancellationToken)
{
_logger.LogError(
exception, "Exception occurred: {Message}", exception.Message);
var problemDetails = new ProblemDetails
{
Status = StatusCodes.Status500InternalServerError,
Title = "Server error"
};
httpContext.Response.StatusCode = problemDetails.Status.Value;
await httpContext.Response
.WriteAsJsonAsync(problemDetails, cancellationToken);
return true;
}
}
internal sealed class GlobalExceptionHandler : IExceptionHandler
{
public async ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
CancellationToken cancellationToken)
{
// Handle the exception, log errors.
return true;
}
}
要将实现添加到 ASP.NET Core 请求管道,需要两件事:IExceptionHandler
调用该方法以将其注册为服务。它注册了单例生存期。因此,在注入具有不同生存期的服务时要小心。AddExceptionHandlerGlobalExceptionHandler
我还调用为常见异常生成问题详细信息响应。AddProblemDetails
builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
builder.Services.AddProblemDetails();
您还需要调用以将 添加到请求管道:
UseExceptionHandlerExceptionHandlerMiddleware
app.UseExceptionHandler();
您可以添加多个实现,并按照注册顺序调用它们。一个可能的用例是使用异常进行流量控制。IExceptionHandler
您可以定义自定义例外,例如 和 。它们与您将从 API 返回的 HTTP 状态代码相对应。BadRequestExceptionNotFoundException
下面是一个实现:BadRequestExceptionHandler
internal sealed class BadRequestExceptionHandler : IExceptionHandler
{
private readonly ILogger<BadRequestExceptionHandler> _logger;
public BadRequestExceptionHandler(ILogger<BadRequestExceptionHandler> logger)
{
_logger = logger;
}
public async ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
CancellationToken cancellationToken)
{
if (exception is not BadRequestException badRequestException)
{
return false;
}
_logger.LogError(
badRequestException,
"Exception occurred: {Message}",
badRequestException.Message);
var problemDetails = new ProblemDetails
{
Status = StatusCodes.Status400BadRequest,
Title = "Bad Request",
Detail = badRequestException.Message
};
httpContext.Response.StatusCode = problemDetails.Status.Value;
await httpContext.Response
.WriteAsJsonAsync(problemDetails, cancellationToken);
return true;
}
}
下面是一个实现:NotFoundExceptionHandler
internal sealed class NotFoundExceptionHandler : IExceptionHandler
{
private readonly ILogger<NotFoundExceptionHandler> _logger;
public NotFoundExceptionHandler(ILogger<NotFoundExceptionHandler> logger)
{
_logger = logger;
}
public async ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
CancellationToken cancellationToken)
{
if (exception is not NotFoundException notFoundException)
{
return false;
}
_logger.LogError(
notFoundException,
"Exception occurred: {Message}",
notFoundException.Message);
var problemDetails = new ProblemDetails
{
Status = StatusCodes.Status404NotFound,
Title = "Not Found",
Detail = notFoundException.Message
};
httpContext.Response.StatusCode = problemDetails.Status.Value;
await httpContext.Response
.WriteAsJsonAsync(problemDetails, cancellationToken);
return true;
}
}
您还需要通过调用以下命令来注册这两个异常处理程序:AddExceptionHandler
builder.Services.AddExceptionHandler<BadRequestExceptionHandler>();
builder.Services.AddExceptionHandler<NotFoundExceptionHandler>();
将首先执行并尝试处理异常。如果未处理异常,则接下来将执行并尝试处理异常。BadRequestExceptionHandlerNotFoundExceptionHandler
在 ASP.NET Core 中使用中间件进行异常处理是一个很好的解决方案。但是,使用该界面的新选项真是太好了。我将在 Core 8 项目中使用 ASP.NET 新方法。IExceptionHandler