110 lines
3.7 KiB
C#
110 lines
3.7 KiB
C#
// <copyright file="ExceptionMiddleware.cs" company="alveus.dev">
|
|
// Copyright (c) alveus.dev. All rights reserved. Licensed under the MIT License.
|
|
// </copyright>
|
|
|
|
using System.Net;
|
|
using Astral.ApiServer.Core;
|
|
using Astral.ApiServer.Models.Common;
|
|
using Astral.Core.Constants;
|
|
using Astral.Core.Exceptions;
|
|
using FluentValidation;
|
|
|
|
namespace Astral.ApiServer.Middleware;
|
|
|
|
/// <summary>
|
|
/// Handle exceptions caught in a request.
|
|
/// </summary>
|
|
public class ExceptionMiddleware
|
|
{
|
|
private readonly ILogger<ExceptionMiddleware> _logger;
|
|
private readonly RequestDelegate _next;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="ExceptionMiddleware" /> class.
|
|
/// </summary>
|
|
/// <param name="next">Instance of <see cref="RequestDelegate" />.</param>
|
|
/// <param name="logger">Instance of <see cref="ILogger" />.</param>
|
|
public ExceptionMiddleware(
|
|
RequestDelegate next,
|
|
ILogger<ExceptionMiddleware> logger)
|
|
{
|
|
_next = next;
|
|
_logger = logger;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invoke middleware.
|
|
/// </summary>
|
|
/// <param name="httpContext">Instance of <see cref="HttpContext" />.</param>
|
|
public async Task InvokeAsync(HttpContext httpContext)
|
|
{
|
|
try
|
|
{
|
|
await _next(httpContext);
|
|
}
|
|
catch (ServiceException exception)
|
|
{
|
|
await HandleServiceExceptionAsync(httpContext, exception);
|
|
}
|
|
catch (ValidationException exception)
|
|
{
|
|
await HandleValidationExceptionAsync(httpContext, exception);
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
_logger.LogError(
|
|
"Unhandled Exception: {path} using {method}: {exception}",
|
|
httpContext.Request.Path,
|
|
httpContext.Request.Method,
|
|
exception);
|
|
await HandleOtherExceptionAsync(httpContext);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Api exception.
|
|
/// </summary>
|
|
/// <param name="context">Instance of <see cref="HttpContext" />.</param>
|
|
/// <param name="exception">Instance of <see cref="ValidationException" />.</param>
|
|
private static async Task HandleServiceExceptionAsync(HttpContext context, ServiceException exception)
|
|
{
|
|
context.Response.ContentType = "application/json";
|
|
context.Response.StatusCode = (int)exception.HttpStatusCode;
|
|
await context.Response.WriteAsJsonAsync(new ErrorResultModel
|
|
{
|
|
Error = exception.ErrorCode,
|
|
Message = exception.ErrorMessage
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Validation failed.
|
|
/// </summary>
|
|
/// <param name="context">Instance of <see cref="HttpContext" />.</param>
|
|
/// <param name="exception">Instance of <see cref="ValidationException" />.</param>
|
|
private static async Task HandleValidationExceptionAsync(HttpContext context, ValidationException exception)
|
|
{
|
|
context.Response.ContentType = "application/json";
|
|
context.Response.StatusCode = StatusCodes.Status422UnprocessableEntity;
|
|
await context.Response.WriteAsJsonAsync(new ErrorResultModel
|
|
{
|
|
Error = CoreErrorCodes.ValidationError,
|
|
Message = exception.Message
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Unexpected exception.
|
|
/// </summary>
|
|
/// <param name="context">Instance of <see cref="HttpContext" />.</param>
|
|
private static async Task HandleOtherExceptionAsync(HttpContext context)
|
|
{
|
|
context.Response.ContentType = "application/json";
|
|
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
|
await context.Response.WriteAsJsonAsync(new ErrorResultModel
|
|
{
|
|
Error = ApiErrorCodes.UnknownError,
|
|
Message = "Something went wrong. Try again later"
|
|
});
|
|
}
|
|
}
|