Thursday, 28 November 2024

IExceptionHandler in.NET Core 8 for Improved Exception Handling

Leave a Comment

Determining how our programs behave requires proper error handling. It involves developing consistent answer formats for our applications so that we can continue to follow a normal process even if something goes wrong. We have a new and improved way to handle problems in our apps thanks to the IExceptionHandler abstraction that comes with.NET 8.

What is an IExceptionHandler?

An interface called IExceptionHandler is used in ASP.NET Core applications to handle exceptions. It outlines an interface that we can use to deal with various exceptions. This enables us to create unique logic that responds to specific exceptions or sets of exceptions according to their type, logging and generating customized error messages and responses.

Why use IExceptionHandler?

We can create more reliable and user-friendly APIs by utilizing IExceptionHandler, which provides a strong and adaptable method for handling exceptions in .NET APIs. In order to handle various exception types, we can also implement IExceptionHandler in standard C# classes. By doing this, we can easily maintain and modularize our applications.

By customizing the responses to the individual exceptions, IExceptionHandler enables us to provide more detailed error messages. This is useful for creating user interfaces that allow us to route users to a specific error page in the event that one of our APIs throws an exception.

Furthermore, because .NET 8 already has the middleware implemented for us through the IExceptionHandler interface, we don't always need to create custom global exception handlers for our applications when using the IExceptionHandler interface.

As an illustration

Let’s create the GlobalExceptionHandler.cs file in our application.

public class GlobalExceptionHandler(ILogger<GlobalExceptionHandler> logger) : IExceptionHandler
{
    private readonly ILogger<GlobalExceptionHandler> _logger = logger;
    public async ValueTask<bool> TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken)
    {
        _logger.LogError(exception, "An unexpected error occurred");
        string? currentId = Activity.Current?.Id ?? httpContext.TraceIdentifier;
        Dictionary<string, object> otherDetails = new()
        {
            { "CurrentId", currentId },
            { "TraceId", Convert.ToString(Activity.Current!.Context.TraceId)! }
        };
        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;
    }
}

Next, let's set up the dependency injection container to register our exception handler.

builder.Services.AddExceptionHandler<GlobalExceptionHandler>();

Our application will automatically call the GlobalExceptionHandler handler whenever an exception occurs. According to RFC 7807 specifications, the API will also produce ProblemDetails standardized responses. We will have more control over how to handle, format, and intercept error responses in this way.

Let's now complete the application request pipeline by adding the middleware:

app.UseExceptionHandler(opt => { });

Let’s run the application and execute the API so we are able to see whether our global exception handler is executing when any exception is raised in our application and showing the details in the API response or not.



Managing various Exception Types

We implement distinct instances of IExceptionHandler, each handling a particular type of exception when handling various error types. Next, by invoking the AddExceptionHandler<THandler>() extension method, we can register each handler in the dependency injection container. It's important to remember that we should register exception handlers in the order in which we want them to be executed.

Let’s create an exception handler to handle The timeout exception handler.

public class TimeoutExceptionHandler(ILogger<TimeoutExceptionHandler> logger) : IExceptionHandler
{
    private readonly ILogger<TimeoutExceptionHandler> _logger = logger;

    public async ValueTask<bool> TryHandleAsync(
        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;
        Dictionary<string, object> otherDetails = new()
        {
            { "CurrentId", currentId },
            { "TraceId", Convert.ToString(Activity.Current!.Context.TraceId)! }
        };
        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;
    }
}

Let’s register the services in the dependency injection.

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

We learned the new technique and evolved together.

Happy coding!

ASP.NET Core 9.0 Hosting Recommendation

One of the most important things when choosing a good ASP.NET Core 9.0 hosting is the feature and reliability. HostForLIFE is the leading provider of Windows hosting and affordable ASP.NET Core, their servers are optimized for PHP web applications. The performance and the uptime of the hosting service are excellent and the features of the web hosting plan are even greater than what many hosting providers ask you to pay for. 

At HostForLIFE.eu, customers can also experience fast ASP.NET Core hosting. The company invested a lot of money to ensure the best and fastest performance of the datacenters, servers, network and other facilities. Its datacenters are equipped with the top equipments like cooling system, fire detection, high speed Internet connection, and so on. That is why HostForLIFEASP.NET guarantees 99.9% uptime for ASP.NET Core. And the engineers do regular maintenance and monitoring works to assure its Orchard hosting are security and always up.

0 comments:

Post a Comment