This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
public interface IExceptionHandler | |
{ | |
public Error HandleException(Exception exception); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.Linq; | |
using System.Net; | |
using FluentValidation; | |
using Microsoft.Extensions.Hosting; | |
using Microsoft.Extensions.Logging; | |
public class ExceptionHandler : IExceptionHandler | |
{ | |
private readonly ILogger<ExceptionHandler> _logger; | |
private readonly IHostEnvironment _environment; | |
public ExceptionHandler(ILogger<ExceptionHandler> logger, | |
IHostEnvironment environment) | |
{ | |
_logger = logger; | |
_environment = environment; | |
} | |
public Error HandleException(Exception exception) | |
{ | |
var error = exception switch | |
{ | |
ValidationException validationException => HandleValidationException(validationException), | |
DomainException domainException => HandleDomainException(domainException), | |
ResourceNotFoundException resourceNotFoundException => HandleResourceNotFoundException(resourceNotFoundException), | |
UnauthorizedException unauthorizedException => HandleUnauthorizedException(unauthorizedException), | |
_ => HandleUnhandledExceptions(exception) | |
}; | |
if (_environment.IsDevelopment()) | |
{ | |
error.Exception = exception.ToString(); | |
} | |
return error; | |
} | |
private Error HandleResourceNotFoundException(ResourceNotFoundException resourceNotFoundException) | |
{ | |
_logger.LogInformation(resourceNotFoundException, resourceNotFoundException.Message); | |
return new Error | |
{ | |
Title = resourceNotFoundException.Message, | |
StatusCode = HttpStatusCode.NotFound, | |
}; | |
} | |
// ValidationException from FluentValidation | |
private Error HandleValidationException(ValidationException validationException) | |
{ | |
_logger.LogInformation(validationException, validationException.Message); | |
var error = new Error | |
{ | |
Title = validationException.Message, | |
StatusCode = HttpStatusCode.BadRequest | |
}; | |
if (validationException.Errors != null && validationException.Errors.Any()) | |
{ | |
error.Entries = new List<ErrorEntry>(); | |
error.Entries.AddRange(validationException.Errors.Select(validationError => | |
new ErrorEntry | |
{ | |
Code = validationError.ErrorCode, | |
Title = validationError.ErrorMessage, | |
Source = validationError.PropertyName | |
})); | |
} | |
return error; | |
} | |
private Error HandleDomainException(DomainException domainException) | |
{ | |
_logger.LogInformation(domainException, domainException.Message); | |
return new Error | |
{ | |
Title = domainException.Message, | |
StatusCode = HttpStatusCode.BadRequest | |
} | |
} | |
private Error HandleUnauthorizedException(UnauthorizedException unauthorizedException) | |
{ | |
_logger.LogInformation(unauthorizedException, unauthorizedException.Message); | |
return new Error | |
{ | |
Title = unauthorizedException.Message, | |
StatusCode = HttpStatusCode.Unauthorized | |
}; | |
} | |
private Error HandleUnhandledExceptions(Exception exception) | |
{ | |
_logger.LogError(exception, exception.Message); | |
return new Error | |
{ | |
Title = "An unhandled error occurred while processing this request", | |
StatusCode = HttpStatusCode.InternalServerError | |
}; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Net.Mime; | |
using System.Text.Json; | |
using System.Threading.Tasks; | |
using Microsoft.AspNetCore.Http; | |
using Microsoft.Extensions.Logging; | |
public class ApplicationExceptionMiddleware | |
{ | |
private readonly RequestDelegate _next; | |
private readonly IExceptionHandler _exceptionHandler; | |
private readonly ILogger<ApplicationExceptionMiddleware> _logger; | |
public ApplicationExceptionMiddleware( | |
RequestDelegate next, | |
IExceptionHandler exceptionHandler, | |
ILogger<ApplicationExceptionMiddleware> logger) | |
{ | |
_next = next; | |
_exceptionHandler = exceptionHandler; | |
_logger = logger; | |
} | |
public async Task InvokeAsync(HttpContext httpContext) | |
{ | |
try | |
{ | |
await _next(httpContext); | |
} | |
catch (Exception ex) | |
{ | |
var error = _exceptionHandler.HandleException(ex); | |
if (!httpContext.Response.HasStarted) | |
{ | |
httpContext.Response.Clear(); | |
httpContext.Response.ContentType = MediaTypeNames.Application.Json; | |
httpContext.Response.StatusCode = (int) errorDocument.StatusCode; | |
await httpContext.Response.WriteAsync(JsonSerializer.Serialize( | |
errorDocument)); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment