using System.Globalization; using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Newtonsoft.Json; namespace Azaion.Common; public class BusinessExceptionHandler(ILogger logger) : IExceptionHandler { public async ValueTask TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken) { if (exception is BusinessException ex) { logger.LogWarning(exception, ex.Message); httpContext.Response.StatusCode = MapStatusCode(ex.ExceptionEnum); httpContext.Response.ContentType = "application/json"; if (ex.RetryAfterSeconds is { } retry && retry > 0) httpContext.Response.Headers.RetryAfter = retry.ToString(CultureInfo.InvariantCulture); var err = JsonConvert.SerializeObject(new { ErrorCode = ex.ExceptionEnum, ex.Message }); await httpContext.Response.WriteAsync(err, cancellationToken).ConfigureAwait(false); return true; } if (exception is BadHttpRequestException badReq) { logger.LogWarning(exception, badReq.Message); httpContext.Response.StatusCode = StatusCodes.Status400BadRequest; httpContext.Response.ContentType = "application/json"; var err = JsonConvert.SerializeObject(new { ErrorCode = 0, badReq.Message }); await httpContext.Response.WriteAsync(err, cancellationToken).ConfigureAwait(false); return true; } return false; } private static int MapStatusCode(ExceptionEnum kind) => kind switch { ExceptionEnum.AccountLocked => StatusCodes.Status423Locked, ExceptionEnum.LoginRateLimited => StatusCodes.Status429TooManyRequests, ExceptionEnum.InvalidRefreshToken => StatusCodes.Status401Unauthorized, ExceptionEnum.SessionNotFound => StatusCodes.Status404NotFound, ExceptionEnum.InvalidMissionRequest => StatusCodes.Status400BadRequest, ExceptionEnum.AircraftNotFound => StatusCodes.Status400BadRequest, _ => StatusCodes.Status409Conflict }; }