Feat Workers Prioridades y Nivel Serilog

This commit is contained in:
2025-09-06 21:44:52 -03:00
parent f384a640f3
commit fa92d9638c
29 changed files with 2068 additions and 95 deletions

View File

@@ -6,6 +6,7 @@ using Elecciones.Core.DTOs.ApiRequests;
using Elecciones.Database.Entities;
using Microsoft.AspNetCore.Authorization;
using Elecciones.Core.Enums;
using Elecciones.Infrastructure.Services;
namespace Elecciones.Api.Controllers;
@@ -16,11 +17,13 @@ public class AdminController : ControllerBase
{
private readonly EleccionesDbContext _dbContext;
private readonly ILogger<AdminController> _logger;
private readonly LoggingSwitchService _loggingSwitchService;
public AdminController(EleccionesDbContext dbContext, ILogger<AdminController> logger)
public AdminController(EleccionesDbContext dbContext, ILogger<AdminController> logger, LoggingSwitchService loggingSwitchService)
{
_dbContext = dbContext;
_logger = logger;
_loggingSwitchService = loggingSwitchService;
}
// Endpoint para obtener todas las agrupaciones para el panel de admin
@@ -297,4 +300,41 @@ public class AdminController : ControllerBase
await _dbContext.SaveChangesAsync();
return NoContent();
}
/// <summary>
/// Actualiza el nivel mínimo de logging en tiempo real y guarda la configuración en la BD.
/// </summary>
/// <param name="request">Un objeto que contiene el nuevo nivel de logging.</param>
[HttpPut("logging-level")]
public async Task<IActionResult> UpdateLoggingLevel([FromBody] UpdateLoggingLevelRequest request)
{
if (string.IsNullOrWhiteSpace(request.Level))
{
return BadRequest("El nivel de logging no puede estar vacío.");
}
// 1. Intentamos actualizar el interruptor de Serilog en memoria.
bool success = _loggingSwitchService.SetLoggingLevel(request.Level);
if (!success)
{
return BadRequest($"El nivel de logging '{request.Level}' no es válido. Los valores posibles son: Verbose, Debug, Information, Warning, Error, Fatal.");
}
// 2. Si el cambio fue exitoso, guardamos el nuevo valor en la base de datos.
var config = await _dbContext.Configuraciones.FindAsync("Logging_Level");
if (config == null)
{
_dbContext.Configuraciones.Add(new Configuracion { Clave = "Logging_Level", Valor = request.Level });
}
else
{
config.Valor = request.Level;
}
await _dbContext.SaveChangesAsync();
_logger.LogWarning("El nivel de logging ha sido cambiado a: {Level}", request.Level);
return Ok(new { message = $"Nivel de logging actualizado a '{request.Level}'." });
}
}

View File

@@ -1,3 +1,4 @@
//Elecciones.Api/Program.cs
using Elecciones.Database;
using Microsoft.EntityFrameworkCore;
using Serilog;
@@ -13,13 +14,24 @@ using Microsoft.AspNetCore.HttpOverrides;
// Esta es la estructura estándar y recomendada.
var builder = WebApplication.CreateBuilder(args);
// 1. Configurar Serilog. Esta es la forma correcta de integrarlo.
builder.Host.UseSerilog((context, services, configuration) => configuration
.ReadFrom.Configuration(context.Configuration)
.ReadFrom.Services(services)
.Enrich.FromLogContext()
.WriteTo.Console()
.WriteTo.File("logs/api-.log", rollingInterval: RollingInterval.Day));
// 1. Registra el servicio del interruptor como un Singleton.
// Esto asegura que toda la aplicación comparta la MISMA instancia del interruptor.
builder.Services.AddSingleton<LoggingSwitchService>();
builder.Host.UseSerilog((context, services, configuration) =>
{
// 2. Obtenemos la instancia del interruptor que acabamos de registrar.
var loggingSwitch = services.GetRequiredService<LoggingSwitchService>();
configuration
.ReadFrom.Configuration(context.Configuration)
.ReadFrom.Services(services)
.Enrich.FromLogContext()
// 3. Establecemos el nivel mínimo de logging controlado por el interruptor.
.MinimumLevel.ControlledBy(loggingSwitch.LevelSwitch)
.WriteTo.Console()
.WriteTo.File("logs/api-.log", rollingInterval: RollingInterval.Day); // o "logs/worker-.log"
});
// 2. Añadir servicios al contenedor.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
@@ -83,6 +95,34 @@ builder.Services.Configure<ForwardedHeadersOptions>(options =>
// 3. Construir la aplicación.
var app = builder.Build();
// --- LÓGICA PARA LEER EL NIVEL DE LOGGING AL INICIO ---
// Creamos un scope temporal para leer la configuración de la BD
using (var scope = app.Services.CreateScope()) // O 'host.Services.CreateScope()'
{
var services = scope.ServiceProvider;
try
{
// El resto de la lógica no cambia
var dbContext = services.GetRequiredService<EleccionesDbContext>();
var loggingSwitchService = services.GetRequiredService<LoggingSwitchService>();
var logLevelConfig = await dbContext.Configuraciones
.AsNoTracking()
.FirstOrDefaultAsync(c => c.Clave == "Logging_Level");
if (logLevelConfig != null)
{
loggingSwitchService.SetLoggingLevel(logLevelConfig.Valor);
Console.WriteLine($"--> Nivel de logging inicial establecido desde la BD a: {logLevelConfig.Valor}");
}
}
catch (Exception ex)
{
// Si hay un error (ej. la BD no está disponible al arrancar), se usará el nivel por defecto 'Information'.
Console.WriteLine($"--> No se pudo establecer el nivel de logging desde la BD: {ex.Message}");
}
}
app.UseForwardedHeaders();
// Seeder para el usuario admin
@@ -150,19 +190,29 @@ using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
var context = services.GetRequiredService<EleccionesDbContext>();
if (!context.Configuraciones.Any(c => c.Clave == "MostrarOcupantes"))
// Lista de configuraciones por defecto a asegurar
var defaultConfiguraciones = new Dictionary<string, string>
{
context.Configuraciones.Add(new Configuracion { Clave = "MostrarOcupantes", Valor = "true" });
context.SaveChanges();
Console.WriteLine("--> Seeded default configuration 'MostrarOcupantes'.");
}
if (!context.Configuraciones.Any(c => c.Clave == "TickerResultadosCantidad"))
{ "MostrarOcupantes", "true" },
{ "TickerResultadosCantidad", "3" },
{ "ConcejalesResultadosCantidad", "5" },
{ "Worker_Resultados_Activado", "false" },
{ "Worker_Bajas_Activado", "false" },
{ "Worker_Prioridad", "Resultados" },
{ "Logging_Level", "Information" }
};
foreach (var config in defaultConfiguraciones)
{
context.Configuraciones.Add(new Configuracion { Clave = "TickerResultadosCantidad", Valor = "3" });
context.Configuraciones.Add(new Configuracion { Clave = "ConcejalesResultadosCantidad", Valor = "5" });
context.SaveChanges();
Console.WriteLine("--> Seeded default configuration 'TickerResultadosCantidad'.");
if (!context.Configuraciones.Any(c => c.Clave == config.Key))
{
context.Configuraciones.Add(new Configuracion { Clave = config.Key, Valor = config.Value });
}
}
context.SaveChanges();
Console.WriteLine("--> Seeded default configurations.");
}
// Configurar el pipeline de peticiones HTTP.

View File

@@ -859,17 +859,17 @@
}
}
},
"Serilog/4.2.0": {
"Serilog/4.3.0": {
"runtime": {
"lib/net9.0/Serilog.dll": {
"assemblyVersion": "4.2.0.0",
"fileVersion": "4.2.0.0"
"assemblyVersion": "4.3.0.0",
"fileVersion": "4.3.0.0"
}
}
},
"Serilog.AspNetCore/9.0.0": {
"dependencies": {
"Serilog": "4.2.0",
"Serilog": "4.3.0",
"Serilog.Extensions.Hosting": "9.0.0",
"Serilog.Formatting.Compact": "3.0.0",
"Serilog.Settings.Configuration": "9.0.0",
@@ -889,7 +889,7 @@
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.8",
"Microsoft.Extensions.Hosting.Abstractions": "9.0.0",
"Microsoft.Extensions.Logging.Abstractions": "9.0.8",
"Serilog": "4.2.0",
"Serilog": "4.3.0",
"Serilog.Extensions.Logging": "9.0.0"
},
"runtime": {
@@ -902,7 +902,7 @@
"Serilog.Extensions.Logging/9.0.0": {
"dependencies": {
"Microsoft.Extensions.Logging": "9.0.8",
"Serilog": "4.2.0"
"Serilog": "4.3.0"
},
"runtime": {
"lib/net9.0/Serilog.Extensions.Logging.dll": {
@@ -913,7 +913,7 @@
},
"Serilog.Formatting.Compact/3.0.0": {
"dependencies": {
"Serilog": "4.2.0"
"Serilog": "4.3.0"
},
"runtime": {
"lib/net8.0/Serilog.Formatting.Compact.dll": {
@@ -926,7 +926,7 @@
"dependencies": {
"Microsoft.Extensions.Configuration.Binder": "9.0.8",
"Microsoft.Extensions.DependencyModel": "9.0.8",
"Serilog": "4.2.0"
"Serilog": "4.3.0"
},
"runtime": {
"lib/net9.0/Serilog.Settings.Configuration.dll": {
@@ -937,7 +937,7 @@
},
"Serilog.Sinks.Console/6.0.0": {
"dependencies": {
"Serilog": "4.2.0"
"Serilog": "4.3.0"
},
"runtime": {
"lib/net8.0/Serilog.Sinks.Console.dll": {
@@ -948,7 +948,7 @@
},
"Serilog.Sinks.Debug/3.0.0": {
"dependencies": {
"Serilog": "4.2.0"
"Serilog": "4.3.0"
},
"runtime": {
"lib/net8.0/Serilog.Sinks.Debug.dll": {
@@ -959,7 +959,7 @@
},
"Serilog.Sinks.File/7.0.0": {
"dependencies": {
"Serilog": "4.2.0"
"Serilog": "4.3.0"
},
"runtime": {
"lib/net9.0/Serilog.Sinks.File.dll": {
@@ -1294,8 +1294,10 @@
"Elecciones.Infrastructure/1.0.0": {
"dependencies": {
"Elecciones.Core": "1.0.0",
"Elecciones.Database": "1.0.0",
"Microsoft.Extensions.Configuration.Abstractions": "9.0.8",
"Microsoft.Extensions.Http": "9.0.8",
"Serilog": "4.3.0",
"System.Threading.RateLimiting": "9.0.8"
},
"runtime": {
@@ -1691,12 +1693,12 @@
"path": "mono.texttemplating/3.0.0",
"hashPath": "mono.texttemplating.3.0.0.nupkg.sha512"
},
"Serilog/4.2.0": {
"Serilog/4.3.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-gmoWVOvKgbME8TYR+gwMf7osROiWAURterc6Rt2dQyX7wtjZYpqFiA/pY6ztjGQKKV62GGCyOcmtP1UKMHgSmA==",
"path": "serilog/4.2.0",
"hashPath": "serilog.4.2.0.nupkg.sha512"
"sha512": "sha512-+cDryFR0GRhsGOnZSKwaDzRRl4MupvJ42FhCE4zhQRVanX0Jpg6WuCBk59OVhVDPmab1bB+nRykAnykYELA9qQ==",
"path": "serilog/4.3.0",
"hashPath": "serilog.4.3.0.nupkg.sha512"
},
"Serilog.AspNetCore/9.0.0": {
"type": "package",

View File

@@ -14,7 +14,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Api")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+d78a02a0ebc4c70ea01e48821db963110e7ce280")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+f384a640f36be1289d652dc85e78ebdcef30968a")]
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Api")]
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Api")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]

View File

@@ -1 +1 @@
{"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["TyIJk/eQMWjmB5LsDE\u002BZIJC9P9ciVxd7bnzRiTZsGt4=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","/GfbpJthEWmsuz0uFx1QLHM7gyM1wLLeQgAIl4SzUD4=","i5\u002B5LcfxQD8meRAkQbVf4wMvjxSE4\u002BjCd2/FdPtMpms=","AvSkxVPIg0GjnB1RJ4hDNyo9p9GONrzDs8uVuixH\u002BOE=","IgT9pOgRnK37qfILj2QcjFoBZ180HMt\u002BScgje2iYOo4=","ezUlOMzNZmyKDIe1wwXqvX\u002BvhwfB992xNVts7r2zcTc=","y2BV4WpkQuLfqQhfOQBtmuzh940c3s4LAopGKfztfTE=","lHTUEsMkDu8nqXtfTwl7FRfgocyyc7RI5O/edTHN1\u002B0=","A7nz7qgOtQ1CwZZLvNnr0b5QZB3fTi3y4i6y7rBIcxQ=","znnuRi2tsk7AACuYo4WSgj7NcLriG4PKVaF4L35SvDk=","GelE32odx/vTului267wqi6zL3abBnF9yvwC2Q66LoM=","TEsXImnzxFKTIq2f5fiDu7i6Ar/cbecW5MZ3z8Wb/a4=","5WogJu\u002BUPlF\u002BE5mq/ILtDXpVwqwmhHtsEB13nmT5JJk=","dcHQRkttjMjo2dvhL7hA9t4Pg\u002B7OnjZpkFmakT4QR9U=","Kt4ImnGs0wklEJp/6NxrhrTvGLQxPfYUAB5LMWAnz10=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","v1SBeIVg8rE3EddYwnvF/EsPYr2F5GAppt/Egvdtr/0="],"CachedAssets":{},"CachedCopyCandidates":{}}
{"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["TyIJk/eQMWjmB5LsDE\u002BZIJC9P9ciVxd7bnzRiTZsGt4=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","/GfbpJthEWmsuz0uFx1QLHM7gyM1wLLeQgAIl4SzUD4=","i5\u002B5LcfxQD8meRAkQbVf4wMvjxSE4\u002BjCd2/FdPtMpms=","AvSkxVPIg0GjnB1RJ4hDNyo9p9GONrzDs8uVuixH\u002BOE=","IgT9pOgRnK37qfILj2QcjFoBZ180HMt\u002BScgje2iYOo4=","ezUlOMzNZmyKDIe1wwXqvX\u002BvhwfB992xNVts7r2zcTc=","y2BV4WpkQuLfqQhfOQBtmuzh940c3s4LAopGKfztfTE=","lHTUEsMkDu8nqXtfTwl7FRfgocyyc7RI5O/edTHN1\u002B0=","A7nz7qgOtQ1CwZZLvNnr0b5QZB3fTi3y4i6y7rBIcxQ=","znnuRi2tsk7AACuYo4WSgj7NcLriG4PKVaF4L35SvDk=","GelE32odx/vTului267wqi6zL3abBnF9yvwC2Q66LoM=","TEsXImnzxFKTIq2f5fiDu7i6Ar/cbecW5MZ3z8Wb/a4=","5WogJu\u002BUPlF\u002BE5mq/ILtDXpVwqwmhHtsEB13nmT5JJk=","dcHQRkttjMjo2dvhL7hA9t4Pg\u002B7OnjZpkFmakT4QR9U=","Of8nTYw5l\u002BgiAJo7z6XYIntG2tUtCFcILzHbTiiXn\u002Bw=","UucupTplk47jbYuQLLfpsVglReDmh1hUE6oD0OEv\u002BsM=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","nor5YuoHu4p8qlladsJ2COw4pycCja0XN1sckUrKV/w="],"CachedAssets":{},"CachedCopyCandidates":{}}

View File

@@ -1 +1 @@
{"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["TyIJk/eQMWjmB5LsDE\u002BZIJC9P9ciVxd7bnzRiTZsGt4=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","/GfbpJthEWmsuz0uFx1QLHM7gyM1wLLeQgAIl4SzUD4=","i5\u002B5LcfxQD8meRAkQbVf4wMvjxSE4\u002BjCd2/FdPtMpms=","AvSkxVPIg0GjnB1RJ4hDNyo9p9GONrzDs8uVuixH\u002BOE=","IgT9pOgRnK37qfILj2QcjFoBZ180HMt\u002BScgje2iYOo4=","ezUlOMzNZmyKDIe1wwXqvX\u002BvhwfB992xNVts7r2zcTc=","y2BV4WpkQuLfqQhfOQBtmuzh940c3s4LAopGKfztfTE=","lHTUEsMkDu8nqXtfTwl7FRfgocyyc7RI5O/edTHN1\u002B0=","A7nz7qgOtQ1CwZZLvNnr0b5QZB3fTi3y4i6y7rBIcxQ=","znnuRi2tsk7AACuYo4WSgj7NcLriG4PKVaF4L35SvDk=","GelE32odx/vTului267wqi6zL3abBnF9yvwC2Q66LoM=","TEsXImnzxFKTIq2f5fiDu7i6Ar/cbecW5MZ3z8Wb/a4=","5WogJu\u002BUPlF\u002BE5mq/ILtDXpVwqwmhHtsEB13nmT5JJk=","dcHQRkttjMjo2dvhL7hA9t4Pg\u002B7OnjZpkFmakT4QR9U=","Kt4ImnGs0wklEJp/6NxrhrTvGLQxPfYUAB5LMWAnz10=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","v1SBeIVg8rE3EddYwnvF/EsPYr2F5GAppt/Egvdtr/0="],"CachedAssets":{},"CachedCopyCandidates":{}}
{"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["TyIJk/eQMWjmB5LsDE\u002BZIJC9P9ciVxd7bnzRiTZsGt4=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","/GfbpJthEWmsuz0uFx1QLHM7gyM1wLLeQgAIl4SzUD4=","i5\u002B5LcfxQD8meRAkQbVf4wMvjxSE4\u002BjCd2/FdPtMpms=","AvSkxVPIg0GjnB1RJ4hDNyo9p9GONrzDs8uVuixH\u002BOE=","IgT9pOgRnK37qfILj2QcjFoBZ180HMt\u002BScgje2iYOo4=","ezUlOMzNZmyKDIe1wwXqvX\u002BvhwfB992xNVts7r2zcTc=","y2BV4WpkQuLfqQhfOQBtmuzh940c3s4LAopGKfztfTE=","lHTUEsMkDu8nqXtfTwl7FRfgocyyc7RI5O/edTHN1\u002B0=","A7nz7qgOtQ1CwZZLvNnr0b5QZB3fTi3y4i6y7rBIcxQ=","znnuRi2tsk7AACuYo4WSgj7NcLriG4PKVaF4L35SvDk=","GelE32odx/vTului267wqi6zL3abBnF9yvwC2Q66LoM=","TEsXImnzxFKTIq2f5fiDu7i6Ar/cbecW5MZ3z8Wb/a4=","5WogJu\u002BUPlF\u002BE5mq/ILtDXpVwqwmhHtsEB13nmT5JJk=","dcHQRkttjMjo2dvhL7hA9t4Pg\u002B7OnjZpkFmakT4QR9U=","Of8nTYw5l\u002BgiAJo7z6XYIntG2tUtCFcILzHbTiiXn\u002Bw=","UucupTplk47jbYuQLLfpsVglReDmh1hUE6oD0OEv\u002BsM=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","nor5YuoHu4p8qlladsJ2COw4pycCja0XN1sckUrKV/w="],"CachedAssets":{},"CachedCopyCandidates":{}}

View File

@@ -287,6 +287,9 @@
"projectReferences": {
"E:\\Elecciones-2025\\Elecciones-Web\\src\\Elecciones.Core\\Elecciones.Core.csproj": {
"projectPath": "E:\\Elecciones-2025\\Elecciones-Web\\src\\Elecciones.Core\\Elecciones.Core.csproj"
},
"E:\\Elecciones-2025\\Elecciones-Web\\src\\Elecciones.Database\\Elecciones.Database.csproj": {
"projectPath": "E:\\Elecciones-2025\\Elecciones-Web\\src\\Elecciones.Database\\Elecciones.Database.csproj"
}
}
}
@@ -315,6 +318,10 @@
"target": "Package",
"version": "[9.0.8, )"
},
"Serilog": {
"target": "Package",
"version": "[4.3.0, )"
},
"System.Threading.RateLimiting": {
"target": "Package",
"version": "[9.0.8, )"