Configuración
Resumen
La configuración de aplicaciones se gestiona a través de la interfaz de usuario del backend. Cada ajuste es un registro en la base de datos representado por la entidad Configuracion, con su valor almacenado como texto plano. Los ajustes se agrupan en clases POCO como ImpuestoConfiguraciones, TemaConfiguraciones, MedioConfiguraciones y ClienteConfiguraciones.
Concepto técnico
Cada clase de configuración debe implementar la interfaz IConfiguraciones y tener un constructor público sin parámetros. El nombre de cada ajuste en la base de datos combina el nombre de la clase y la propiedad (ejemplo: TemaConfiguraciones.TemaPredeterminado).
Solo las propiedades públicas con getter y setter son elegibles como configuraciones persistentes. El sistema de conversión de tipos de la aplicación convierte valores entre tipos, pero se recomienda evitar tipos complejos en las propiedades de configuración.
Las entradas de configuración soportan múltiples organizaciones, permitiendo sobrescribir valores a nivel organizacional.
Acceso a configuraciones
Mediante inyección de dependencias
Las clases que implementan IConfiguraciones se registran automáticamente como dependencias singleton:
private readonly MiConfiguraciones1 _miConfiguraciones1;
private readonly MiConfiguraciones2 _miConfiguraciones2;
public MiFalsoServicio(MiConfiguraciones1 miConfiguraciones1, MiConfiguraciones2 miConfiguraciones2)
{
_miConfiguraciones1 = miConfiguraciones1;
_miConfiguraciones2 = miConfiguraciones2;
}
No se deben actualizar programáticamente las propiedades de configuración, ya que los cambios persisten en la aplicación en ejecución.
Mediante IConfiguracionFabrica
El singleton IConfiguracionFabrica es responsable de activar e instanciar clases de configuración. El método CargarConfiguracionesAsync<TConfiguraciones>() carga desde caché o base de datos, mientras que GuardarConfiguracionesAsync<TConfiguraciones>() guarda cambios:
public async Task ActualizarConfiguracionesAsync(string nombre, int organizacionId)
{
var miConfiguraciones = await Servicios.ConfiguracionFabrica.CargarConfiguracionesAsync<MiConfiguraciones>(organizacionId);
miConfiguraciones.Nombre = nombre;
await Servicios.ConfiguracionFabrica.GuardarConfiguracionesAsync(miConfiguraciones, organizacionId);
}
Acceso a entradas individuales
El servicio IConfiguracionServicio permite acceder a entradas individuales. Actualizar entradas invalida automáticamente la caché de clases relacionadas.
Tutorial
Crear la clase de configuración
public class PerfiladorConfiguraciones : IConfiguraciones
{
public bool MiniPerfiladorEnPaginaPublicaHabilitado { get; set; }
public string[] MiniPerfiladorRutasIgnoradas { get; set; } = new[] { "/admin/", "/temas/", "/agrupacion/" };
public bool MostrarZonasMicroAplicacion { get; set; }
public bool MostrarNombreMaquina { get; set; }
}
Crear el modelo de configuración
Separar la interfaz de usuario de las capas de aplicación es una buena práctica:
[LocalizadoMostrar("Complementos.Desarrollo.HerramientasDesarrollo.")]
public class ConfiguracionModelo : ModeloBase
{
[LocalizadoMostrar("*MiniPerfiladorEnPaginaPublicaHabilitado")]
public bool MiniPerfiladorEnPaginaPublicaHabilitado { get; set; }
[UIHint("Textarea"), MetadatosAdicional("rows", 2)]
[LocalizadoMostrar("*MiniPerfiladorRutasIgnoradas")]
public string MiniPerfiladorRutasIgnoradas { get; set; }
[LocalizadoMostrar("*MostrarZonasMicroAplicacion")]
public bool MostrarZonasMicroAplicacion { get; set; }
[LocalizadoMostrar("*MostrarNombreMaquina")]
public bool MostrarNombreMaquina { get; set; }
}
Crear vista
@model ConfiguracionModelo
@{
Layout = "_ConfigurarModulo";
}
@await Component.InvokeAsync("AmbitoOrganizacion")
<form asp-action="Configurar">
<microaplicacion zona-destino="admin_boton_barraherramienta_antes">
<button id="btnGuardarConfiguracion" type="submit" name="guardar" class="btn btn-warning btn-sm" value="guardar">
<i class="fa fa-check"></i>
<span>@T("Admin.Comun.Guardar")</span>
</button>
</microaplicacion>
<div asp-validation-summary="All"></div>
<div class="adminContenido">
<div class="adminFila">
<div class="adminTitulo">
<crono-etiqueta asp-for="MiniPerfiladorEnPaginaPublicaHabilitado" />
</div>
<div class="adminDatos">
<editor-configuracion asp-for="MiniPerfiladorEnPaginaPublicaHabilitado" data-toggle-para="#pnlRutasIgnoradas"></editor-configuracion>
<span asp-validation-for="MiniPerfiladorEnPaginaPublicaHabilitado"></span>
</div>
</div>
<div id="pnlRutasIgnoradas" class="adminFila">
<div class="adminTitulo">
<crono-etiqueta asp-for="MiniPerfiladorRutasIgnoradas" />
</div>
<div class="adminDatos">
<editor-configuracion asp-for="MiniPerfiladorRutasIgnoradas"></editor-configuracion>
<span asp-validation-for="MiniPerfiladorRutasIgnoradas"></span>
</div>
</div>
<div class="adminFila">
<div class="adminTitulo">
<crono-etiqueta asp-for="MostrarZonasMicroAplicacion" />
</div>
<div class="adminDatos">
<editor-configuracion asp-for="MostrarZonasMicroAplicacion"></editor-configuracion>
<span asp-validation-for="MostrarZonasMicroAplicacion"></span>
</div>
</div>
<div class="adminFila">
<div class="adminTitulo">
<crono-etiqueta asp-for="MostrarNombreMaquina" />
</div>
<div class="adminDatos">
<editor-configuracion asp-for="MostrarNombreMaquina"></editor-configuracion>
<span asp-validation-for="MostrarNombreMaquina"></span>
</div>
</div>
</div>
</form>
Crear acciones del controlador
Usa los atributos CargarConfiguracion y GuardarConfiguracion para simplificar el código:
[Route("[area]/herramientasdesarrollo/{action=index}/{id?}")]
public class HerramientasDesarrolloController : ModuloController
{
[AutorizarAdmin, Permiso(HerramientasDesarrolloPermisos.Leer)]
[CargarConfiguracion]
public IActionResult Configurar(PerfiladorConfiguraciones configuraciones)
{
var modelo = MapeadorMini.Mapear<PerfiladorConfiguraciones, ConfiguracionModelo>(configuraciones);
return View(modelo);
}
[AutorizarAdmin, Permiso(HerramientasDesarrolloPermisos.Actualizar)]
[HttpPost, GuardarConfiguracion]
public IActionResult Configurar(ConfiguracionModelo modelo, PerfiladorConfiguraciones configuraciones)
{
if (!ModelState.IsValid)
{
return Configurar(configuraciones);
}
ModelState.Clear();
MapeadorMini.Mapear(modelo, configuraciones);
return RedirectToAction(nameof(Configurar));
}
}
Crear un elemento de menú
Consulta la documentación sobre Menús para integrar la página de configuraciones en el backend.