What if part of the service throws an exception? Handling exceptions is a crucial part of the development process of services. As we saw in Chapter 7, Filter Pipeline, it is possible to use them to catch exceptions using a filter. Filters are one of the crucial parts of the MVC stack: they act before and after action methods, and they can be used to log exceptions in a single implementation. Let's have a look at JsonExceptionAttribute in Catalog.API again:
using System.Net;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using Catalog.API.Exceptions;
namespace Catalog.API.Filters
{
public class JsonExceptionAttribute : TypeFilterAttribute
{
public JsonExceptionAttribute() : base(typeof(HttpCustomExceptionFilterImpl))
{
}
public class HttpCustomExceptionFilterImpl : IExceptionFilter
{
private readonly IHostingEnvironment _env;
private readonly ILogger _logger;
public HttpCustomExceptionFilterImpl(IHostingEnvironment
env,
ILogger<HttpCustomExceptionFilterImpl> logger)
{
_env = env;
_logger = logger;
}
public void OnException(ExceptionContext context)
{
var eventId = new EventId(context.Exception.HResult);
_logger.LogError(eventId, context.Exception,
context.Exception.Message);
var json = new JsonErrorPayload
{
EventId = eventId.Id
};
json.DetailedMessage = context.Exception;
var exceptionObject = new ObjectResult(json) {
StatusCode = 500 };
context.Result = exceptionObject;
context.HttpContext.Response.StatusCode = (int)
HttpStatusCode.InternalServerError;
}
}
}
}
The class tracks and returns exceptions using the analog pattern, which can be seen in the implementation of the handler: the ILogger<T> interface is injected into the constructor using dependency injection and the _logger.LogError method.
In the next section, we will learn how to verify logging in our test using Moq.