using Microsoft.AspNetCore.Diagnostics; using PARR.API.Contracts.V1.Responses.Base; using PARR.Domain.Exceptions; namespace PARR.API.Infrastructure.Middleware { /// /// Глобальная обработка ошибок согласно моих кастомных Exception /// public class GlobalExceptionHandler : IExceptionHandler { private readonly ILogger logger; public GlobalExceptionHandler(ILogger logger) { this.logger = logger; } public async ValueTask TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken) { logger.LogError(exception, "Ошибка во время запроса {TraceId}: {Message}", httpContext.TraceIdentifier, exception.Message); // определяем статус код, в зависимости от типа исключения var statusCode = exception switch { NotFoundException => StatusCodes.Status404NotFound, DbErrorException => StatusCodes.Status502BadGateway, ExternalServiceException => StatusCodes.Status502BadGateway, AppValidationException => StatusCodes.Status400BadRequest, FluentValidation.ValidationException => StatusCodes.Status400BadRequest, AlreadyExistsException => StatusCodes.Status409Conflict, UnauthorizedException => StatusCodes.Status401Unauthorized, ForbiddenException => StatusCodes.Status403Forbidden, //todo: ---------- другие ошибки ---------- _ => StatusCodes.Status500InternalServerError }; // Для критических серверных ошибок (5xx) пишем детальный лог if (statusCode >= 500) { logger.LogError(exception, "Критическая ошибка сервера: {Message}", exception.Message); } //var errorMessage = exception.Message; var errors = new List(); // Если это ошибка FluentValidatioun, вытаскиваем детали по каждому полю if (exception is FluentValidation.ValidationException fluentEx) { // ошибка валидации, вернем по каждому полю foreach (var error in fluentEx.Errors) { errors.Add(new ErrorModel { FieldName = error.PropertyName, Message = error.ErrorMessage }); } } else { // это не ошибка валидации, вернем сообщение errors.Add(new ErrorModel { Message = exception.Message }); } httpContext.Response.StatusCode = statusCode; var response = new Response(null, false, errors, exception.Message); await httpContext.Response.WriteAsJsonAsync(response, cancellationToken); // ошибка обработана return true; } } }