在 .NET Core 8 中使用 IExceptionHandler 增强了异常处理

发布:2024-11-28 14:28 阅读:105 点赞:0

在.NET 8中,异常处理是通过接口来实现的,它为开发者提供了一种统一的方式来处理应用程序中的异常。以下是对上述内容的中文介绍:IExceptionHandler

介绍

合适的错误处理对于确定应用程序的行为至关重要。它需要为我们的应用程序创建统一的响应格式,这样,即使出现错误,我们也可以保持标准程序。.NET 8 中引入的 抽象为我们提供了一种新的、更好的方法来处理应用程序中的错误。IExceptionHandler

什么是 IExceptionHandler?

在 ASP.NET Core 应用程序中, 接口被用来处理异常。它定义了一个我们可以用来处理各种异常的接口。这使我们能够创建独特的逻辑,根据异常类型响应特定的异常或异常集合,记录并生成自定义的错误消息和响应。IExceptionHandler

为什么使用 IExceptionHandler?

我们可以利用 创建更可靠且用户友好的 API。 为处理 .NET API 中的异常提供了一种强大且适应性强的方法。为了处理各种异常类型,我们还可以在标准 C# 类中实现 。通过这样做,我们可以轻松地维护和模块化我们的应用程序。IExceptionHandlerIExceptionHandlerIExceptionHandler

通过自定义对各个异常的响应, 使我们能够提供更详细的错误消息。这对于创建用户界面非常有用,这些用户界面允许我们在其中一个 API 引发异常时将用户路由到特定的错误页面。IExceptionHandler

举个例子

让我们在应用程序中创建 文件。GlobalExceptionHandler.cs

public class GlobalExceptionHandler : IExceptionHandler
{
    private readonly ILogger<GlobalExceptionHandler> _logger;

    public GlobalExceptionHandler(ILogger<GlobalExceptionHandler> logger)
    {
        _logger = logger;
    }

    public async ValueTask<boolTryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken)
    {
        _logger.LogError(exception, "An unexpected error occurred");
        string? currentId = Activity.Current?.Id ?? httpContext.TraceIdentifier;
        var otherDetails = new Dictionary<stringobject>
        {
            { "CurrentId", currentId },
            { "TraceId", Activity.Current?.Context.TraceId.ToString() }
        };
        await httpContext.Response.WriteAsJsonAsync(
            new ProblemDetails
            {
                Status = (int)HttpStatusCode.InternalServerError,
                Type = exception.GetType().Name,
                Title = "An unexpected error occurred",
                Detail = exception.Message,
                Instance = $"{httpContext.Request.Method} {httpContext.Request.Path}",
                Extensions = otherDetails
            },
            cancellationToken);
        return true;
    }
}

接下来,让我们设置依赖项注入容器来注册我们的异常处理程序。

builder.Services.AddExceptionHandler<GlobalExceptionHandler>();

每当发生异常时,我们的应用程序将自动调用 处理程序。根据 RFC 7807 规范,API 还将生成 标准化响应。我们将对如何以这种方式处理、格式化和拦截错误响应有更多的控制权。GlobalExceptionHandlerProblemDetails

现在,让我们通过添加中间件来完成应用程序请求管道:

app.UseExceptionHandler(opt => { });

让我们运行应用程序并执行 API,以便我们能够查看在应用程序中引发任何异常时全局异常处理程序是否正在执行,并在 API 响应中显示详细信息。

API Response

管理各种异常类型

我们实现了 的不同实例,每个实例在处理各种错误类型时处理特定类型的异常。接下来,通过调用 扩展方法,我们可以在依赖项注入容器中注册每个处理程序。请务必记住,我们应该按照我们希望执行的顺序注册异常处理程序。IExceptionHandlerAddExceptionHandler<THandler>()

让我们创建一个异常处理程序来处理超时异常。

public class TimeoutExceptionHandler : IExceptionHandler
{
    private readonly ILogger<TimeoutExceptionHandler> _logger;

    public TimeoutExceptionHandler(ILogger<TimeoutExceptionHander> logger)
    {
        _logger = logger;
    }

    public async ValueTask<boolTryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken)
    {
        _logger.LogError(exception, "A timeout occurred");
        if (exception is not TimeoutException)
        {
            return false;
        }
        httpContext.Response.StatusCode = (int)HttpStatusCode.RequestTimeout;
        string? currentId = Activity.Current?.Id ?? httpContext.TraceIdentifier;
        var otherDetails = new Dictionary<stringobject>
        {
            { "CurrentId", currentId },
            { "TraceId", Activity.Current?.Context.TraceId.ToString() }
        };
        await httpContext.Response.WriteAsJsonAsync(
            new ProblemDetails
            {
                Status = (int)HttpStatusCode.RequestTimeout,
                Type = exception.GetType().Name,
                Title = "A timeout occurred",
                Detail = exception.Message,
                Instance = $"{httpContext.Request.Method} {httpContext.Request.Path}",
                Extensions = otherDetails
            },
            cancellationToken);
        return true;
    }
}

让我们在依赖项注入中注册服务。

builder.Services.AddExceptionHandler<TimeoutExceptionHandler>();
builder.Services.AddExceptionHandler<GlobalExceptionHandler>();

Public class

Request URL

通过这种方式,我们可以为不同的异常类型提供特定的处理逻辑,并且可以灵活地控制错误响应的格式和内容。