Adding a global exception handler

When an unhandled exception is thrown from a controller action, ASP.NET Core responds to the caller with the status code 500 (Internal Server Error). For the client, this status code means that something bad happened on the server but doesn't offer any meaningful information that the user can provide to the API support team (such as the request/correlation identifier).

To overcome this, we need to add a global exception handler — a piece of code that can intercept the calls made to the request pipeline and catch exceptions that were thrown. There is more than one way to add a global exception handler, but I believe the easiest way is by adding an Exception Filter that will be added to the MVC pipeline.

To create an Exception Filter, you need to implement the Microsoft.AspNetCore.Mvc.Filters.IExceptionFilter interface and provide an implementation of the OnException() method that will be called whenever there's an unhandled exception.

The following implementation intercepts the unhandled exception and creates an object with details about the error. If the application is in development mode, the exception details are returned as well:

public class GlobalExceptionFilter : IExceptionFilter
{
private readonly IHostingEnvironment env;
private readonly ILogger<GlobalExceptionFilter> _logger;

public GlobalExceptionFilter(IHostingEnvironment env, ILogger<GlobalExceptionFilter> logger)
{
this.env = env;
this._logger = logger;
}

public void OnException(ExceptionContext context)
{
_logger.LogError(new EventId(context.Exception.HResult),
context.Exception,
context.Exception.Message);

var errorDetails = new ErrorDetails()
{
Instance = context.HttpContext.Request.Path,
Status = StatusCodes.Status500InternalServerError,
Detail = "Please refer to the errors property for additional details.",
Errors =
{
{"ServerError", new[] {"An unexpected error ocurred."}}
},
};

if (env.IsDevelopment())
{
errorDetails.Exception = context.Exception;
}

context.Result = new ObjectResult(errorDetails)
{
StatusCode = StatusCodes.Status500InternalServerError
};
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

context.ExceptionHandled = true;
}

private class ErrorDetails : ValidationProblemDetails
{
public Exception Exception { get; set; }
}
}

The ErrorDetails type is the DTO I'm using for returning the error details in the response. It derives from the Microsoft.AspNetCore.Mvc.ValidationProblemDetails class that implements the RFC 7807 standard (https://tools.ietf.org/html/rfc7807), a standardized format for carrying machine-readable details of errors in HTTP responses.

In your application, you can extend the GlobalExceptionFilter so that if an application-specific exception is caught, it will change the error message appropriately.

To add GlobalExceptionFilter to the request pipeline, you need to register it in the Startup class as part of the MVC services inside the ConfigureServices method:

public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(config =>
{
...
config.Filters.Add<GlobalExceptionFilter>();
});
...
}

Now, when sending a request that generates an error, we get, in response, a structured format to work with: 

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.206.69