Skip to main content

Validación

FluentValidation

Crono usa FluentValidation para crear reglas de validación fuertemente tipadas sobre los modelos de vista, del lado del servidor. Se definen reglas para las propiedades del modelo asociado; cuando el valor cambia en una página de edición, se valida contra su regla y, si no se cumple, se emite un mensaje de error. Por convención, la clase validadora se ubica junto al modelo de vista, en el mismo archivo.

La clase de un validador hereda de AbstractValidator, al que se le pasa el tipo del modelo de vista como parámetro genérico:

public partial class ClienteValidador : AbstractValidator<ClienteModelo>
{
public ClienteValidador(ClienteConfiguraciones configuraciones)
{
RuleFor(x => x.Clave).NotEmpty().When(x => x.Id == 0);

if (configuraciones.NombreRequerido)
RuleFor(x => x.Nombre).NotEmpty();

if (configuraciones.TelefonoRequerido)
RuleFor(x => x.Telefono).NotEmpty();

// Código omitido para mayor claridad.
}
}

FluentValidation permite expresar reglas complejas (por ejemplo, validar un correo, comprobar que dos campos coinciden, o validar una lista de valores con Must(...)), y personalizar el mensaje con WithMessage(...).

CronoValidador

Normalmente las propiedades del modelo de vista tienen los mismos nombres que la entidad o la clase de configuración correspondiente, de modo que sus valores se copian con una sola sentencia de MapeadorMini (ver Mapeo de modelos). Esto permite a Crono ofrecer utilidades adicionales mediante la clase base CronoValidador<TModelo>.

CronoValidador<TModelo> (que hereda de AbstractValidator<TModelo>) copia reglas de validación comunes desde el tipo de entidad hacia el modelo con AplicarEntidadReglas<TEntidad>. Las reglas comunes son Required y MaxLength sobre propiedades de cadena (definidas por API fluida o por anotaciones). También añade la regla Required a los tipos de valor no anulables del modelo. Con AplicarNoNuloValorTipoReglas puedes aplicar solo esa última parte.

public partial class BancoValidador : CronoValidador<BancoModelo>
{
public BancoValidador(CronoDbContexto db)
{
AplicarEntidadReglas<Banco>(db);
}
}
info

Puedes evitar errores de validación y solicitudes de soporte recortando ciertos datos antes de guardarlos, sobre todo aquellos que nunca empiezan o terminan con espacio (accesos de API, cuentas bancarias, claves). Recorta con un ayudante seguro antes de mapear al destino.

Validador de configuración

ConfiguracionModeloValidador<TModelo, TConfiguracion> es un validador abstracto para las páginas de configuración que puede ignorar reglas de propiedades de configuración que no están marcadas en una sesión de edición específica de organización. Expone AmbitoOrganizacion y EsConfiguraciónSobrescrita(rutaPropiedad) para decidir cuándo aplicar cada regla según si el valor está sobrescrito para la organización actual.

Validación manual

Usa IValidator para validar un modelo manualmente:

private readonly IValidator<PagoModelo> _validador;

public async Task<bool> ValidarAsync(PagoModelo modelo)
{
var resultado = await _validador.ValidateAsync(modelo);
return resultado.IsValid;
}

Validación de MVC

Como Crono se basa en ASP.NET Core MVC, también están disponibles las validaciones del lado servidor y cliente del framework.

Del lado del servidor

El ModelState representa los errores del enlace de modelos (model binding) y de la validación. Si el ModelState no es válido, no se deben guardar datos: se recarga la página de edición con los errores.

[CargarConfiguracion]
public IActionResult Configurar(MiConfiguraciones configuraciones)
{
var modelo = MapeadorMini.Mapear<MiConfiguraciones, ConfiguracionModelo>(configuraciones);
return View(modelo);
}

[HttpPost, GuardarConfiguracion]
public IActionResult Configurar(ConfiguracionModelo modelo, MiConfiguraciones configuraciones)
{
if (!ModelState.IsValid)
{
return Configurar(configuraciones);
}

ModelState.Clear();
MapeadorMini.Mapear(modelo, configuraciones);
return RedirectToAction(nameof(Configurar));
}
info

Cuando el ModelState es inválido, el método GET debe llamarse directamente (sin redirigir), o los errores de validación se perderán.

Los atributos de DataAnnotations permiten especificar reglas sobre las propiedades del modelo. Los más comunes son Required, StringLength, Range, Compare, EmailAddress, RegularExpression, Url y ValidateNever. También puedes agregar errores personalizados:

if (modelo.Correo.EstaVacio())
{
ModelState.AddModelError(nameof(modelo.Correo), T("Cuenta.Registro.Errores.CorreoNoIngresado"));
}

Si la clave (primer parámetro) es string.Empty, el error se muestra en el resumen de validación y no junto a un campo concreto.

En la vista, el resumen y los mensajes por campo se renderizan con los tag helpers estándar:

<div asp-validation-summary="All"></div>
<span asp-validation-for="BancoId"></span>
info

En formularios dentro de pestañas conviene usar ValidationSummary.All; de lo contrario el usuario podría no ver el mensaje de error.

Del lado del cliente

La validación del cliente impide enviar el formulario hasta que sea válido, evitando viajes innecesarios al servidor. Los mensajes se corresponden con los atributos de validación del modelo. Ten en cuenta que las validaciones de cliente y servidor pueden diferir: por ejemplo, un campo de cadena con solo espacios se considera válido en el cliente, pero el servidor lo trata como inválido si es requerido.