public async Task Invoke(HttpContext context) { try { await _next(context); } catch (BaseApiException ex) { var statusCode = _mapper.GetExceptionHandlerReturnCode(ex); _logger.LogDebug(ex, "Mapped BaseApiException of type {ExceptionType} caught, decorating response status code: {StatusCode}.", ex.GetType(), statusCode.ToString()); context.Response.StatusCode = (int)statusCode; throw; } catch (ApiException ex) { _logger.LogDebug(ex, "ApiException caught, decorating response status code: {StatusCode}.", ex.StatusCode.ToString()); context.Response.StatusCode = (int)ex.StatusCode; throw; } catch (Exception ex) { _logger.LogDebug(ex, "Exception caught, decorating response status code: {StatusCode}.", HttpStatusCode.InternalServerError.ToString()); context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; throw; } }
internal static ApiError Build <TCategoryName>(HttpContext context, Exception ex, IExceptionMapper mapper, ILogger <TCategoryName> logger, bool isDevelopment) { context.Response.ContentType = "application/json"; HttpStatusCode statusCode; int errorCode; object developerContext = null; switch (ex) { case BaseApiException _: try { developerContext = (ex as BaseApiException)?.DeveloperContext; errorCode = mapper.GetErrorCode(ex as BaseApiException); statusCode = mapper.GetExceptionHandlerReturnCode(ex as BaseApiException); context.Response.StatusCode = (int)statusCode; logger.LogInformation(ex, "Mapped BaseApiException of type {exceptionType} caught by ApiExceptionHandler. Will return with {statusCodeInt} {statusCodeString}. Unexpected: {unexpected}", ex.GetType(), (int)statusCode, statusCode.ToString(), false); } catch (ArgumentException) { goto default; } break; case ApiException _: errorCode = -2; statusCode = (ex as ApiException).StatusCode; context.Response.StatusCode = (int)statusCode; logger.LogInformation(ex, "ApiException caught by ApiExceptionHandler with {statusCodeInt} {statusCodeString}. Unexpected: {unexpected}", (int)statusCode, statusCode.ToString(), false); break; default: errorCode = -1; statusCode = HttpStatusCode.InternalServerError; context.Response.StatusCode = (int)statusCode; logger.LogError(ex, "Unhandled exception of type {exceptionType} caught by ApiExceptionHandler. Will return with {statusCodeInt} {statusCodeString}. Unexpected: {unexpected}", ex.GetType(), (int)statusCode, statusCode.ToString(), true); break; } var error = new ApiError(mapper.Options.ServiceName) { CorrelationId = context.TraceIdentifier, DeveloperContext = developerContext, ErrorCode = errorCode, }; if (isDevelopment) { error.Message = ex.Message; error.DetailedMessage = ex.ToAsyncString(); } else { error.Message = Regex.Replace(statusCode.ToString(), "[a-z][A-Z]", m => m.Value[0] + " " + char.ToLower(m.Value[1])); error.DetailedMessage = ex.Message; } return(error); }
internal static ApiError Build <TCategoryName>(HttpContext context, Exception ex, IExceptionMapper mapper, ILogger <TCategoryName> logger, bool isDevelopment, Action <Exception>[] exceptionListeners) { //Execute custom exception handlers first. foreach (var customExceptionListener in exceptionListeners) { try { customExceptionListener.Invoke(ex); } catch (Exception e) { logger.LogWarning(e, "Custom exception listener {exceptionListener} threw an exception.", customExceptionListener.GetType().ToString()); } } context.Response.ContentType = "application/json"; HttpStatusCode statusCode; (int errorCode, string error)errorObject; object developerContext = null; object exceptionContext = new {}; switch (ex) { case BaseApiException baseApiException: try { if (mapper.Options.RespondWithDeveloperContext) { developerContext = baseApiException.DeveloperContext; } exceptionContext = baseApiException.Context; errorObject = mapper.GetError(baseApiException); statusCode = mapper.GetExceptionHandlerReturnCode(baseApiException); context.Response.StatusCode = (int)statusCode; logger.LogInformation(ex, "Mapped BaseApiException of type {exceptionType} caught by ApiExceptionHandler. Will return with {statusCodeInt} {statusCodeString}. Unexpected: {unexpected}", ex.GetType(), (int)statusCode, statusCode.ToString(), false); } catch (ArgumentException) { goto default; } break; case OperationCanceledException _: errorObject = (-1, "Frogvall.AspNetCore.ExceptionHandling.OperationCanceled"); statusCode = HttpStatusCode.InternalServerError; context.Response.StatusCode = (int)statusCode; logger.LogWarning(ex, "OperationCanceledException exception caught by ApiExceptionHandler. Will return with {statusCodeInt} {statusCodeString}. Unexpected: {unexpected}", (int)statusCode, statusCode.ToString(), true); break; default: errorObject = (-1, "Frogvall.AspNetCore.ExceptionHandling.InternalServerError"); statusCode = HttpStatusCode.InternalServerError; context.Response.StatusCode = (int)statusCode; logger.LogError(ex, "Unhandled exception of type {exceptionType} caught by ApiExceptionHandler. Will return with {statusCodeInt} {statusCodeString}. Unexpected: {unexpected}", ex.GetType(), (int)statusCode, statusCode.ToString(), true); break; } var error = new ApiError(mapper.Options.ServiceName) { CorrelationId = context.TraceIdentifier, Context = exceptionContext, DeveloperContext = developerContext, ErrorCode = errorObject.errorCode, Error = errorObject.error }; if (isDevelopment) { error.Message = ex.Message; error.DetailedMessage = ex.ToString(); } else { error.Message = Regex.Replace(statusCode.ToString(), "[a-z][A-Z]", m => m.Value[0] + " " + char.ToLower(m.Value[1])); error.DetailedMessage = ex.Message; } return(error); }