74 lines
2.7 KiB
C#
74 lines
2.7 KiB
C#
|
|
using GestionIntegral.Api.Services.Contables;
|
||
|
|
using Microsoft.AspNetCore.Http;
|
||
|
|
using Microsoft.Extensions.Logging;
|
||
|
|
using System;
|
||
|
|
using System.Text.Json;
|
||
|
|
using System.Threading.Tasks;
|
||
|
|
|
||
|
|
namespace GestionIntegral.Api.Middleware
|
||
|
|
{
|
||
|
|
// Centraliza el mapeo de excepciones semánticas a HTTP responses con cuerpo JSON estandarizado.
|
||
|
|
// Va PRIMERO en el pipeline para catchear cualquier excepción que escape de los controllers/services.
|
||
|
|
public class ExceptionHandlerMiddleware
|
||
|
|
{
|
||
|
|
private readonly RequestDelegate _next;
|
||
|
|
private readonly ILogger<ExceptionHandlerMiddleware> _logger;
|
||
|
|
|
||
|
|
private static readonly JsonSerializerOptions JsonOptions = new()
|
||
|
|
{
|
||
|
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||
|
|
};
|
||
|
|
|
||
|
|
public ExceptionHandlerMiddleware(RequestDelegate next, ILogger<ExceptionHandlerMiddleware> logger)
|
||
|
|
{
|
||
|
|
_next = next;
|
||
|
|
_logger = logger;
|
||
|
|
}
|
||
|
|
|
||
|
|
public async Task InvokeAsync(HttpContext context)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
await _next(context);
|
||
|
|
}
|
||
|
|
catch (BloqueoPorPeriodoCerradoException ex)
|
||
|
|
{
|
||
|
|
_logger.LogWarning(
|
||
|
|
"Bloqueo por período cerrado: cierre #{IdCierre} FechaCorte={FechaCorte:yyyy-MM-dd}. Path={Path}",
|
||
|
|
ex.IdCierre, ex.FechaCorte, context.Request.Path);
|
||
|
|
|
||
|
|
await WriteJsonAsync(context, StatusCodes.Status409Conflict, new
|
||
|
|
{
|
||
|
|
codigo = "PERIODO_CERRADO_BLOQUEO_OPERACION",
|
||
|
|
mensaje = ex.Message,
|
||
|
|
idCierre = ex.IdCierre,
|
||
|
|
fechaCorte = ex.FechaCorte.ToString("yyyy-MM-dd")
|
||
|
|
});
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
_logger.LogError(ex, "Excepción no manejada. Path={Path}", context.Request.Path);
|
||
|
|
|
||
|
|
await WriteJsonAsync(context, StatusCodes.Status500InternalServerError, new
|
||
|
|
{
|
||
|
|
codigo = "ERROR_INTERNO",
|
||
|
|
mensaje = "Ocurrió un error inesperado al procesar la solicitud."
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private static Task WriteJsonAsync(HttpContext context, int statusCode, object body)
|
||
|
|
{
|
||
|
|
if (context.Response.HasStarted)
|
||
|
|
{
|
||
|
|
// Si los headers ya se enviaron no podemos re-escribir el response. Solo loguear y salir.
|
||
|
|
return Task.CompletedTask;
|
||
|
|
}
|
||
|
|
context.Response.Clear();
|
||
|
|
context.Response.StatusCode = statusCode;
|
||
|
|
context.Response.ContentType = "application/json; charset=utf-8";
|
||
|
|
return context.Response.WriteAsync(JsonSerializer.Serialize(body, JsonOptions));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|