Reec.Inspection.SqlServer
8.0.21
dotnet add package Reec.Inspection.SqlServer --version 8.0.21
NuGet\Install-Package Reec.Inspection.SqlServer -Version 8.0.21
<PackageReference Include="Reec.Inspection.SqlServer" Version="8.0.21" />
<PackageVersion Include="Reec.Inspection.SqlServer" Version="8.0.21" />
<PackageReference Include="Reec.Inspection.SqlServer" />
paket add Reec.Inspection.SqlServer --version 8.0.21
#r "nuget: Reec.Inspection.SqlServer, 8.0.21"
#:package Reec.Inspection.SqlServer@8.0.21
#addin nuget:?package=Reec.Inspection.SqlServer&version=8.0.21
#tool nuget:?package=Reec.Inspection.SqlServer&version=8.0.21
🚀 Reec.Inspection — Observabilidad ligera y trazabilidad para aplicaciones .NET
Reec.Inspection es una librería de observabilidad ligera para aplicaciones .NET 8+ que centraliza:
- Auditoría de solicitudes HTTP entrantes.
- Captura automática de errores del pipeline.
- Ejecución segura de tareas en segundo plano.
- Registro de llamadas a servicios externos con resiliencia.
- Limpieza automática de logs mediante workers en segundo plano.
Todo esto usando Entity Framework Core y una configuración sencilla basada en opciones (ReecExceptionOptions).
⚡ Guía rápida
Si solo quieres verlo funcionando en minutos, sigue esta sección.
Para más detalles, baja a la 👉 Guía completa.
📦 Instalación (NuGet)
dotnet add package Reec.Inspection
dotnet add package Reec.Inspection.SqlServer
🧰 Configuración mínima (Program.cs)
builder.Services.AddReecInspection<InspectionDbContext>(
options => options.UseSqlServer(builder.Configuration.GetConnectionString("default")),
options =>
{
options.ApplicationName = "Reec.Inspection.Api"; // Obligatorio
options.SystemTimeZoneId = "SA Pacific Standard Time"; // Recomendado
options.EnableProblemDetails = true; // Opcional
});
var app = builder.Build();
app.UseReecInspection(); // Registra los middlewares de auditoría y captura de errores
app.MapControllers();
app.Run();
Con esto obtienes:
- Middleware de auditoría (
LogAudit) para requests HTTP. - Middleware de errores (
LogHttp) para excepciones no controladas. - Workers de limpieza de logs, si están habilitados en las opciones.
⚙️ Ejemplo rápido de captura de errores
[HttpGet("error")]
public IActionResult GetError()
{
var x = 1 / 0; // Error intencional
return Ok();
}
Ese error se registra automáticamente en la tabla LogHttp (y puede devolverse como ProblemDetails si está activado).
🕒 Limpieza automática de logs
Ejemplo rápido para LogAudit:
options.LogAudit.EnableClean = true;
options.LogAudit.CronValue = "0 2 * * *"; // Todos los días a las 2 a.m.
options.LogAudit.DeleteDays = 10; // Mantiene solo los últimos 10 días
Cada tipo (LogAudit, LogHttp, LogEndpoint, LogJob) tiene su propio worker de limpieza opcional.
💝 Apoya el desarrollo continuo
Si Reec.Inspection está ayudando a optimizar tu trabajo y te gustaría contribuir al desarrollo continuo de esta librería, puedes hacerlo a través de Plin (Perú):
<div align="center">
<img src="images/QR Plin.jpeg" alt="Plin QR Code" width="300"/>
Yape/Plin
</div>
Tu apoyo ayuda a mantener el proyecto actualizado con nuevas características, correcciones de bugs y documentación mejorada. ¡Toda contribución es valorada! 🙏
🧭 Guía completa
Índice
- Configuración inicial
- Versión legacy vs nueva
- Configuración de
ReecExceptionOptions - Importancia de
SystemTimeZoneId - Registro de
ApplicationName - Guardado condicional (
EnableGlobalDbSave/IsSaveDB) - Captura de errores (
LogHttp,LogAudit) - Ejecución de tareas en segundo plano (
IWorker) - Resiliencia en peticiones HTTP (
AddReecInspectionResilience) - Migración con otro proveedor de base de datos
- Buenas prácticas y sugerencias
- Manejo de excepciones controladas (Modo Legacy)
- Manejo de excepciones con ProblemDetails (Modo Actual)
- Estado del proyecto
1. Configuración inicial
Registro principal en Program.cs:
builder.Services.AddReecInspection<InspectionDbContext>(
options => options.UseSqlServer(builder.Configuration.GetConnectionString("default")),
options =>
{
options.ApplicationName = "Reec.Inspection.Api";
options.SystemTimeZoneId = "SA Pacific Standard Time";
options.EnableProblemDetails = true;
options.EnableGlobalDbSave = true;
});
var app = builder.Build();
app.UseReecInspection();
AddReecInspection:
- Registra el
DbContextderivado deInspectionDbContextconDbContextPool. - Registra middlewares (
LogAuditMiddleware,LogHttpMiddleware). - Registra
IWorker,IDateTimeServicey workers de limpieza (CleanLog*Worker) según configuración. - Opcionalmente agrega soporte
ProblemDetails.
UseReecInspection:
- Agrega al pipeline los middlewares de auditoría y captura de errores según
ReecExceptionOptions.
Orden recomendado:
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseReecInspection();
app.MapControllers();
2. Versión legacy vs nueva
AddReecException<TDbContext> (Legacy)
- Se mantiene con
[Obsolete]para compatibilidad. - Usar solo en proyectos existentes.
AddReecInspection<TDbContext> (Recomendado)
- Nueva API principal.
- Usa
DbContextPool. - Configura
ReecExceptionOptionsmedianteAction<ReecExceptionOptions>. - Integra hosted services de limpieza y
IWorker.
Ejemplo:
builder.Services.AddReecInspection<InspectionDbContext>(
options => options.UseSqlServer(connString),
options =>
{
options.ApplicationName = "MyService.Api";
options.EnableGlobalDbSave = true;
options.LogHttp.IsSaveDB = true;
options.LogAudit.IsSaveDB = true;
});
3. Configuración de ReecExceptionOptions
ReecExceptionOptions centraliza la configuración global.
Propiedades principales
| Propiedad | Descripción | Default |
|---|---|---|
ApplicationName |
Nombre de la app que genera los logs. | null |
ApplicationErrorMessage |
Mensaje mostrado cuando ocurre un error al intentar guardar información en la base de datos. | Ocurrió un error al guardar log en Base de Datos. |
InternalServerErrorMessage |
Mensaje genérico utilizado para errores internos del sistema. | Error no controlado del sistema. |
SystemTimeZoneId |
Zona horaria usada para registrar fechas y programar cron. | "SA Pacific Standard Time" |
EnableMigrations |
Ejecuta migraciones automáticas al inicio. | true |
EnableProblemDetails |
Respuestas de error en formato ProblemDetails. |
false |
EnableGlobalDbSave |
Habilita/deshabilita escritura global en BD. | true |
MinCategory |
Categoría mínima a registrar. | Unauthorized (401) |
Secciones por tipo de log
Cada módulo tiene opciones propias (LogAudit, LogHttp, LogJob, LogEndpoint):
Schema: esquema de base de datos.TableName: nombre de la tabla.IsSaveDB: habilita/deshabilita persistencia.EnableClean: activa worker de limpieza.CronValue: expresión CRON para limpieza.DeleteDays: días hacia atrás a conservar.DeleteBatch: tamaño del lote de borrado.
Ejemplo para LogAudit con tablas existentes (sin migraciones):
options.EnableMigrations = false;
options.LogAudit.Schema = "Inspection";
options.LogAudit.TableName = "LogAudit";
options.LogAudit.IsSaveDB = true;
options.LogAudit.EnableClean = true;
options.LogAudit.CronValue = "0 2 * * *";
options.LogAudit.DeleteDays = 15;
options.LogAudit.DeleteBatch = 500;
Aplica el mismo patrón para LogHttp, LogJob y LogEndpoint.
4. Importancia de SystemTimeZoneId
Todas las fechas registradas en los logs y workers usan esta zona horaria:
- Fechas de creación.
- Ejecuciones de jobs.
- Cálculo de
CronValue.
options.SystemTimeZoneId = "SA Pacific Standard Time";
Para ver las zonas disponibles:
var zones = TimeZoneInfo.GetSystemTimeZones();
Si el ID es inválido, la inicialización de IDateTimeService lanzará excepción.
5. Registro de ApplicationName
Obligatorio para distinguir qué sistema originó cada registro.
options.ApplicationName = "Billing.Api";
Se utiliza en todas las tablas de log como columna de referencia.
6. Guardado condicional
Global
options.EnableGlobalDbSave = true; // Si es false, no se persisten logs en BD.
Por módulo
options.LogAudit.IsSaveDB = true;
options.LogHttp.IsSaveDB = true;
options.LogJob.IsSaveDB = true;
options.LogEndpoint.IsSaveDB = true;
Desactivar por módulo es útil para escenarios donde solo quieres ciertos tipos de trazas.
7. Captura de errores (LogHttp, LogAudit)
LogHttp — Errores del pipeline
Ejemplo:
[HttpGet("test-error")]
public IActionResult TestError()
{
var value = 10 / 0;
return Ok(value);
}
LogHttpMiddleware:
- Intercepta excepciones no controladas.
- Registra
Exception,StackTrace,Path,TraceIdentifier, etc. - Puede responder en
ProblemDetailssi está habilitado.
LogAudit — Auditoría HTTP
LogAuditMiddleware:
- Registra método, ruta, estado, tiempos, opcionalmente cuerpo de request/response.
- Respeta:
ExcludePathsRequestBodyMaxSizeResponseBodyMaxSizeEnableBuffering
Ejemplo de exclusión:
options.LogAudit.ExcludePaths = new[] { "swagger", "health", "index" };
8. Ejecución de tareas en segundo plano (IWorker)
IWorker expone:
RunFunction: lógica principal.RunFunctionException: manejo custom de errores.IsLightExecution: solo registra fallos cuando estrue.- Estados (
Enqueued,Processing,Succeeded,Failed) enLogJob.
8.1 Modo persistente (HostedService)
Uso recomendado para jobs periódicos (patrón similar a los CleanLog*Worker).
public class SampleJobWorker : BackgroundService
{
private readonly IServiceScopeFactory _scopeFactory;
public SampleJobWorker(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
using var scope = _scopeFactory.CreateScope();
var worker = scope.ServiceProvider.GetRequiredService<IWorker>();
worker.NameJob = nameof(SampleJobWorker);
worker.CreateUser = "System";
worker.IsLightExecution = false;
worker.RunFunction = service => ProcessAsync(service, stoppingToken);
await worker.ExecuteAsync(stoppingToken);
}
}
private static async Task<string> ProcessAsync(IServiceProvider services, CancellationToken ct)
{
var dbContextService = services.GetRequiredService<IDbContextService>();
var db = dbContextService.GetDbContext();
// Lógica de negocio aquí
await Task.Delay(1000, ct);
return "Proceso completado correctamente.";
}
}
Registrar el worker:
builder.Services.AddHostedService<SampleJobWorker>();
8.2 Modo "fire-and-forget" disparado desde un request
Para iniciar una tarea en segundo plano desde un endpoint HTTP sin bloquear la respuesta:
[ApiController]
[Route("api/[controller]")]
public class JobsController : ControllerBase
{
private readonly IServiceScopeFactory _scopeFactory;
public JobsController(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
[HttpPost("start-clean-temp")]
public IActionResult StartCleanTemp()
{
var scope = _scopeFactory.CreateScope();
var worker = scope.ServiceProvider.GetRequiredService<IWorker>();
worker.NameJob = "CleanTemporaryFiles";
worker.CreateUser = "System";
worker.IsLightExecution = true;
worker.RunFunction = svc => ProcessAsync(svc);
_ = worker.ExecuteAsync().ContinueWith(_ =>
{
scope.Dispose();
});
return Ok("Tarea en segundo plano iniciada.");
}
private static async Task<string> ProcessAsync(IServiceProvider services)
{
var dbContextService = services.GetRequiredService<IDbContextService>();
var db = dbContextService.GetDbContext();
// Lógica puntual
await Task.Delay(2000);
return "Limpieza de temporales completada.";
}
}
Notas:
- No se usa
Task.Runexterno:IWorkermaneja la ejecución asíncrona y logging. - No se espera el resultado, pero el job queda registrado en
LogJob.
9. Resiliencia en peticiones HTTP (AddReecInspectionResilience)
Esta extensión integra:
LogEndpointHandler: registra requests/responses a servicios externos.- Pipeline estándar de resiliencia (timeout, retry, circuit breaker).
Registro
var httpBuilder = builder.Services.AddHttpClient("PlaceHolder", httpClient =>
{
httpClient.DefaultRequestHeaders.Clear();
httpClient.BaseAddress = new Uri("https://jsonplaceholder.typicode.com");
});
builder.Services.AddReecInspectionResilience(httpBuilder);
Uso:
public class ExternalController : ControllerBase
{
private readonly IHttpClientFactory _httpClientFactory;
public ExternalController(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
[HttpGet("posts")]
public async Task<IActionResult> GetPosts()
{
var client = _httpClientFactory.CreateClient("PlaceHolder");
var response = await client.GetAsync("/posts");
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
return Content(content, "application/json");
}
}
AddReecInspectionResilience configura por defecto:
- Timeout total: 1 minuto (personalizable).
- Reintentos con backoff exponencial.
- Circuit breaker con metadatos en
HttpRequestMessage.Options.
10. Migración con otro proveedor de base de datos
Para usar PostgreSQL (u otro proveedor soportado por EF Core), hereda de InspectionDbContext y genera una migración:
public class InspectionPgContext : InspectionDbContext
{
public InspectionPgContext(DbContextOptions<InspectionPgContext> options)
: base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Ejemplo: esquema por defecto
modelBuilder.HasDefaultSchema("inspection");
}
}
Registro:
builder.Services.AddReecInspection<InspectionPgContext>(
options => options.UseNpgsql(builder.Configuration.GetConnectionString("Postgres")),
options =>
{
options.ApplicationName = "Reec.Pg.Api";
options.EnableMigrations = true; // O manejar migraciones externamente
});
11. Buenas prácticas y sugerencias
- Configura siempre
ApplicationNameySystemTimeZoneId. - Considera desactivar
EnableMigrationsen producción y aplicar migraciones vía CI/CD. - Usa
Schemadedicado (ej."Inspection") para aislar tus tablas de log. - Ajusta
DeleteDaysyDeleteBatchsegún volumen de logs. - Usa
IsLightExecution = truepara jobs muy frecuentes donde solo te interesen errores. - Excluye rutas sensibles de
LogAudit(swagger,health, etc.). - Asegúrate de no registrar cuerpos que contengan datos sensibles sin anonimizar.
12. Manejo de excepciones controladas (Modo Legacy)
Reec.Inspection mantiene compatibilidad total con el sistema de excepciones del proyecto Reec original mediante ReecException y ReecMessage.
Este modo es útil cuando:
- Migras desde Reec a Reec.Inspection.
- Necesitas mantener contratos de respuesta existentes con clientes.
- Prefieres un formato de respuesta personalizado sobre RFC 7807 (ProblemDetails).
12.1. Configuración
Para usar el modo legacy, establece EnableProblemDetails = false (es el valor por defecto):
builder.Services.AddReecInspection<InspectionDbContext>(
options => options.UseSqlServer(connString),
options =>
{
options.ApplicationName = "Legacy.Api";
options.EnableProblemDetails = false; // Modo legacy activado
});
12.2. Categorías de error disponibles
Las categorías están definidas en el enum Category y representan diferentes tipos de respuestas:
| Categoría | Valor | HTTP Status | Uso |
|---|---|---|---|
OK |
200 | 200 | Operación exitosa |
PartialContent |
206 | 206 | Consulta exitosa sin contenido |
Unauthorized |
401 | 401 | Autenticación requerida |
Forbidden |
403 | 403 | Sin permisos suficientes |
Warning |
460 | 400 | Validación de campos |
BusinessLogic |
465 | 400 | Errores controlados de negocio |
BusinessLogicLegacy |
470 | 400 | Errores controlados de sistemas externos |
InternalServerError |
500 | 500 | Errores no controlados |
BadGateway |
502 | 502 | Error en sistema externo |
GatewayTimeout |
504 | 504 | Timeout en sistema externo |
12.3. Formas de uso
a) Mensaje simple
[HttpPost("create-user")]
public IActionResult CreateUser(CreateUserRequest request)
{
if (string.IsNullOrWhiteSpace(request.Email))
{
throw new ReecException(Category.Warning, "El correo electrónico es obligatorio.");
}
// Lógica de creación...
return Ok();
}
Respuesta JSON:
{
"id": 42,
"path": "/create-user",
"traceIdentifier": "0HNGTMGA752BQ:00000001",
"category": 460,
"categoryDescription": "Warning",
"message": ["El correo electrónico es obligatorio."]
}
b) Lista de mensajes
[HttpPost("validate-form")]
public IActionResult ValidateForm(FormData data)
{
var errors = new List<string>();
if (string.IsNullOrWhiteSpace(data.Name))
errors.Add("El nombre es obligatorio.");
if (data.Age < 18)
errors.Add("Debe ser mayor de 18 años.");
if (errors.Any())
{
throw new ReecException(Category.Warning, errors);
}
return Ok();
}
Respuesta JSON:
{
"id": 43,
"path": "/validate-form",
"traceIdentifier": "0HNGTMGA752BQ:00000002",
"category": 460,
"categoryDescription": "Warning",
"message": [
"El nombre es obligatorio.",
"Debe ser mayor de 18 años."
]
}
c) Error de lógica de negocio
[HttpPost("transfer")]
public IActionResult Transfer(TransferRequest request)
{
var account = GetAccount(request.AccountId);
if (account.Balance < request.Amount)
{
throw new ReecException(
Category.BusinessLogic,
"Saldo insuficiente para realizar la transferencia."
);
}
// Procesar transferencia...
return Ok();
}
Respuesta JSON:
{
"id": 44,
"path": "/transfer",
"traceIdentifier": "0HNGTMGA752BQ:00000003",
"category": 465,
"categoryDescription": "Business Logic",
"message": ["Saldo insuficiente para realizar la transferencia."]
}
d) Captura de excepción con contexto
[HttpPost("import-data")]
public IActionResult ImportData(ImportRequest request)
{
try
{
var result = ExternalService.ProcessFile(request.FilePath);
return Ok(result);
}
catch (Exception ex)
{
throw new ReecException(
Category.BusinessLogicLegacy,
"Error al procesar el archivo de importación.",
ex.Message // ExceptionMessage original
);
}
}
Respuesta JSON:
{
"id": 45,
"path": "/import-data",
"traceIdentifier": "0HNGTMGA752BQ:00000004",
"category": 470,
"categoryDescription": "Business Logic Legacy",
"message": ["Error al procesar el archivo de importación."]
}
Nota: En la base de datos (
LogHttp), el campoExceptionMessagecontendrá el mensaje original de la excepción, mientras queMessageUserguarda el mensaje amigable para el cliente.
e) Excepción con InnerException
[HttpGet("external-data")]
public async Task<IActionResult> GetExternalData()
{
try
{
var client = _httpClientFactory.CreateClient("ExternalApi");
var response = await client.GetAsync("/data");
response.EnsureSuccessStatusCode();
return Ok(await response.Content.ReadAsStringAsync());
}
catch (HttpRequestException ex)
{
throw new ReecException(
Category.BadGateway,
"No se pudo conectar con el servicio externo.",
ex.Message,
ex.InnerException // Se preserva InnerException
);
}
}
12.4. Comportamiento del middleware
LogHttpMiddleware detecta automáticamente si la excepción es del tipo ReecException:
- Extrae el
ReecMessageconfigurado. - Asigna el
HttpStatusCodesegún la categoría:Warning,BusinessLogic,BusinessLogicLegacy→ 400 Bad Request- Otras categorías → Usan su código numérico directo.
- Persiste el log en la tabla
LogHttp(si está habilitado). - Devuelve el objeto
ReecMessageserializado como JSON.
12.5. Ventajas del modo Legacy
✅ Retrocompatibilidad: Los clientes existentes siguen funcionando sin cambios.
✅ Flexibilidad: Control total sobre la estructura de respuesta.
✅ Trazabilidad: Cada error registra un Id único en base de datos.
✅ Claridad: Las categorías personalizadas son más descriptivas que códigos HTTP estándar.
13. Manejo de excepciones con ProblemDetails (Modo Actual)
Reec.Inspection soporta el estándar RFC 7807 (Problem Details for HTTP APIs) para respuestas de error estructuradas y consistentes.
Este modo es recomendado cuando:
- Construyes APIs nuevas siguiendo estándares de la industria.
- Necesitas interoperabilidad con frameworks y herramientas que esperan RFC 7807.
- Quieres aprovechar características de ASP.NET Core como
UseExceptionHandler.
13.1. Configuración
Para activar el modo ProblemDetails, establece EnableProblemDetails = true:
builder.Services.AddReecInspection<InspectionDbContext>(
options => options.UseSqlServer(connString),
options =>
{
options.ApplicationName = "Modern.Api";
options.EnableProblemDetails = true; // Modo actual activado
options.InternalServerErrorMessage = "Error no controlado del sistema.";
});
13.2. Estructura de respuesta
Cuando ocurre una excepción, la respuesta sigue el formato estándar RFC 7807:
{
"title": "Internal Server Error",
"status": 500,
"detail": "Error no controlado del sistema.",
"instance": "/api/demo/error",
"id": 1,
"category": 500,
"traceIdentifier": "0HNGTMGA752BQ:00000003"
}
Campos de la respuesta
| Campo | Tipo | Descripción |
|---|---|---|
title |
string | Nombre legible de la categoría de error |
status |
int | Código HTTP estándar |
detail |
string | Mensaje de error descriptivo para el usuario |
instance |
string | Path del endpoint que generó el error |
id |
int | ID del registro en la tabla LogHttp (0 si no se guardó) |
category |
int | Código de categoría interno (compatible con modo legacy) |
traceIdentifier |
string | Identificador único para correlación de logs |
13.3. Ejemplo de captura automática
El middleware captura automáticamente cualquier excepción no controlada:
[ApiController]
[Route("api/[controller]")]
public class DemoController : ControllerBase
{
[HttpGet("InternalServerError")]
public IActionResult InternalServerError()
{
var numerador = 1;
var denominador = 0;
var dividendo = numerador / denominador; // DivideByZeroException
return Ok(dividendo);
}
}
Request:
GET /api/demo/InternalServerError
Response (500 Internal Server Error):
{
"title": "Internal Server Error",
"status": 500,
"detail": "Error no controlado del sistema.",
"instance": "/api/demo/InternalServerError",
"id": 1,
"category": 500,
"traceIdentifier": "0HNGTMGA752BQ:00000003"
}
13.4. Compatibilidad con ReecException
Aunque uses ProblemDetails, puedes seguir lanzando ReecException para controlar la categoría:
[HttpPost("validate")]
public IActionResult Validate(UserInput input)
{
if (string.IsNullOrWhiteSpace(input.Email))
{
throw new ReecException(
Category.Warning,
"El correo electrónico es obligatorio."
);
}
return Ok();
}
Response (400 Bad Request):
{
"title": "Warning",
"status": 400,
"detail": "El correo electrónico es obligatorio.",
"instance": "/validate",
"id": 2,
"category": 460,
"traceIdentifier": "0HNGTMGA752BQ:00000004"
}
13.5. Códigos de estado HTTP
El middleware mapea las categorías personalizadas a códigos HTTP estándar:
| Categoría | Código Interno | HTTP Status | Title |
|---|---|---|---|
OK |
200 | 200 | OK |
PartialContent |
206 | 206 | Partial Content |
Unauthorized |
401 | 401 | Unauthorized |
Forbidden |
403 | 403 | Forbidden |
Warning |
460 | 400 | Warning |
BusinessLogic |
465 | 400 | Business Logic |
BusinessLogicLegacy |
470 | 400 | Business Logic Legacy |
InternalServerError |
500 | 500 | Internal Server Error |
BadGateway |
502 | 502 | Bad Gateway |
GatewayTimeout |
504 | 504 | Gateway Timeout |
Importante: Las categorías
Warning,BusinessLogicyBusinessLogicLegacyse traducen a 400 Bad Request para cumplir con los estándares HTTP.
13.6. Detección de ProblemDetails
Todas las respuestas de error en modo ProblemDetails incluyen un header personalizado:
EnableProblemDetails: true
Esto permite a los clientes detectar automáticamente el formato de respuesta.
13.7. Persistencia en base de datos
Independientemente del formato de respuesta (Legacy o ProblemDetails), todos los errores se registran en la tabla LogHttp con:
- Timestamp con zona horaria configurada
- Stack trace completo
- Request body (si está habilitado buffering)
- Headers filtrados según configuración
- Categoría y mensaje de error
- Duración de la petición
13.8. Ventajas del modo ProblemDetails
✅ Estándar RFC 7807: Compatible con herramientas y bibliotecas de la industria.
✅ Integración nativa: Funciona con UseExceptionHandler de ASP.NET Core.
✅ Extensibilidad: Puedes agregar propiedades personalizadas en Extensions.
✅ Herramientas: Swagger, Postman y otros clientes entienden el formato automáticamente.
✅ Trazabilidad: Mantiene traceIdentifier para correlación con logs.
13.9. Comparación con el modo Legacy
| Aspecto | Modo Legacy | Modo ProblemDetails |
|---|---|---|
| Formato | ReecMessage personalizado |
RFC 7807 estándar |
| Retrocompatibilidad | ✅ Con Reec original | ❌ Requiere actualizar clientes |
| Estándar industria | ❌ | ✅ |
| Categorías custom | ✅ 460, 465, 470 | ✅ Traducidas a 400 |
| Tooling support | ⚠️ Limitado | ✅ Amplio |
| Persistencia BD | ✅ | ✅ |
| TraceIdentifier | ✅ | ✅ |
14. Estado del proyecto
- Repositorio: github.com/edychumpitaz/ReecInspection
- Proyecto Legacy: github.com/edychumpitaz/Reec (mantenido para referencia)
- Autor: Edy Chumpitaz
- Licencia: MIT
- Estado: Desarrollo activo 🚧
- Próximamente: Documentación completa estilo ReadTheDocs
Roadmap
- Proveedores adicionales (PostgreSQL, MySQL, MongoDB, Oracle)
- Métricas y alertas configurables
- Dashboard de visualización de logs
Contribuciones
¿Tienes ideas, sugerencias o encontraste un bug?
- 🐛 Reporta issues: GitHub Issues
- 💡 Propón mejoras: GitHub Discussions
- 🔀 Envía Pull Requests: Son bienvenidos siguiendo las convenciones del proyecto
Nota: Este proyecto es una reescritura completa del proyecto original Reec, con arquitectura mejorada, soporte para .NET 8+, y nuevas características como workers de limpieza, resiliencia HTTP y modos de respuesta intercambiables.
<div align="center">
Construido con ❤️ para la comunidad .NET
⭐ Dale una estrella en GitHub si te fue útil
</div>
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.EntityFrameworkCore.SqlServer (>= 8.0.21)
- Reec.Inspection (>= 8.0.21)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Versión 8.0.21
• Actualización de Entity Framework Core a 8.0.21
• Sincronización con Reec.Inspection 8.0.21
• Mejoras en las migraciones para tablas de log
• Optimizaciones de performance en escritura de alta concurrencia