¿Sabías que puedes validar un formulario de html fácil, rápido y sencillo con ASP Net Core?

En este tutorial os voy a enseñar a como validar un formulario mediante DataAnnotations a través de un model.

Antes de comenzar con el tutorial os voy a explicar que son los DataAnnotations.

Los DataAnnotations son nos permite llevar a cabo validaciones de datos de acuerdo a nuestras necesidades. Esas necesidades son decoraciones que indicaremos a los miembros de nuestras entidades. Una decoración corresponderá a una validación. Hay mútiples tipos de validaciones desde un teléfono, un email, rangos entre dos números, etc. Os voy a dejar un enlace donde podréis ver todas:

https://learn.microsoft.com/es-es/aspnet/core/mvc/models/validation?view=aspnetcore-7.0

Lo primero que debemos hacer es crear un proyecto, en este caso para hacer las pruebas vamos a crear un proyecto de tipo:

ASP.NET Core Web App (Model-View-Controller)

tipo

No creará un proyecto ya configurado y con Bootstrap (última versión).

A continuación, crearemos un model llamado Usuario. En este caso creamos propiedades diversas para hacer probar diferentes DataAnnotations: Nombre, Apellidos, Edad, Email, Fecha de nacimiento, Contraseña y repetir contraseña.

Sobre Models creamos nuestro model:

public class Usuario
    {
        [Required(ErrorMessage = "Este campo es requerido.")]
        [MinLength(5, ErrorMessage = "El nombre debe tener mínimo 5 caracteres")]
        [MaxLength(10, ErrorMessage = "El nombre debe tener máximo 10 caracteres")]
        public string Nombre { get; set; }

        [Required(ErrorMessage = "Este campo es requerido.")]
        [StringLength(4, ErrorMessage = "The ThumbnailPhotoFileName value cannot exceed 4 characters. ")]
        public string Apellidos { get; set; }

        [Required(ErrorMessage = "Este campo es requerido.")]
        [Range(18,65, ErrorMessage = "La edad comprende entre 18 y 65")]
        public int Edad { get; set; }

        [Required(ErrorMessage = "Este campo es requerido.")]
        [EmailAddress(ErrorMessage = "Formato incorrecto")]
        public string Email { get; set; }

        [Required(ErrorMessage = "Este campo es requerido.")]
        [RegularExpression(@"^(?=\w*\d)(?=\w*[A-Z])(?=\w*[a-z])\S{8,16}$", ErrorMessage = "La contraseña debe tener entre 8 y 16 caracteres, al menos un dígito, al menos una minúscula y al menos una mayúscula.")]
        public string Contraseña { get; set; }

        [Required(ErrorMessage = "Este campo es requerido.")]
        [Compare("Contraseña", ErrorMessage = "Las contraseñas no coinciden.")]
        public string RepetirContraseña { get; set; }
    }

Required describe que el campo es obligatorio. MinLength describe la longitud mínima de un string. MaxLength, describe la longitud máxima de un string. Range describe el valor mínimo en número y valor máximo en número. RegularExpression describe una expresión regular con mensaje de error correspondiente. Compare describe una comparación de igualdad con otro campo, en este caso Contraseña.

Ahora bien seguro que te estas preguntando, que pasaría si quisiera tener una validación con lógica, por ejemplo un DNi, del cuál puedes hacer una expresión regular pero no puedes saber si los número corresponden a la letra asignada. Para ello existen las validaciones de personalizadas, donde mediante la implementación de ValidationAttribute podemos crear tantas validaciones personalizadas como quieras.

Para ver como funciona esto añadiremos un nuevo campo en nuestro model Usuario:

public string Dni { get; set; }

Para llevar a cabo esta validación crearemos una carpeta Validations donde nos creamos una clase llamada ValidationDNI.

Una vez tengamos la clase creado, sobrescribiremos el método isValid():

public class ValidationDNI: ValidationAttribute
{
   public override bool IsValid(object? value)
   {
       return false
   }
}

Éste método recibirá un objeto de cualquier tipo, donde si devolvemos false, la validación será incorrecta y si devolvemos true la validación será correcta.

Para realizar esta validación he creado un Helper de validaciones ya que la validación del DNI es un poco compleja y prefiero separarlo pero si quieres podría hacer aquí directamente. Creamos una carpeta Helpers y una clase HelperValidation con el siguiente código:

public static class HelperValidation
    {
        public static bool CheckDNI(string dni)
        {
            if (dni.Length != 9)
            {
                return false;
            }

            string dniNumbers = dni.Substring(0, dni.Length - 1);
            string dniLeter = dni.Substring(dni.Length - 1, 1);
            var numbersValid = int.TryParse(dniNumbers, out int dniInteger);
            if (!numbersValid)
            {
                return false;
            }
            if (CalculateDNILeter(dniInteger) != dniLeter)
            {
                return false;
            }
            return true;
        }

        private static string CalculateDNILeter(int dniNumbers)
        {
            string[] control = { "T", "R", "W", "A", "G", "M", "Y", "F", "P", "D", "X", "B", "N", "J", "Z", "S", "Q", "V", "H", "L", "C", "K", "E" };
            var mod = dniNumbers % 23;
            return control[mod];
        }
    }

Una vez tengamos esto, llamaremos a este helper desde nuestra clase ValidationDNI quedando de esta forma:

public class ValidationDNI: ValidationAttribute
{
    public override bool IsValid(object? value)
    {
       if (value is not null)
       {
          return HelperValidation.CheckDNI((string)value);
       }
       else
       {
          return false;
       }
    }
}

Pues listo chicos, sólo queda el último paso, incluirlo en nuestro model Usuario. Para ello, llamaremos a nuestra clase entre [] y como hereda de ValidationAttribute podemos añadirle todas las propiedades de cualquier validación.

Quedando nuestro DNI así:

[Required(ErrorMessage = "Este campo es requerido.")]
[ValidationDNI(ErrorMessage = "Formato incorrecto")]
public string Dni { get; set; }

Para comprobar que las validación funcionan crearemos un Controller llamado UsuarioController donde incluiremos los siguientes IActionResult:

public class UsuarioController : Controller
{
   public IActionResult Registro()
   {
      return View();
   }

   [HttpPost]
   public IActionResult Registro(Usuario usuario)
   {
      if (!ModelState.IsValid)
      {
         ViewData["Error"] = "Datos incorrectos";
         return View();
      }

      return View();
    }
}

Como has podido comprobar en el método post recibimos el usuario validado. Este usuario no es obligatorio recibirlo para validar ya que cuando invocamos alguna model con DataAnnotations se guarda el resultado en una especia de estado. Por lo que debemos comprobar ese estado mediante ModelState.isValid. Esto devolverá un true o un false dependiendo si es correcto o no.

Una vez explicado esto, tendremos que crear un html con un formulario. Para que la explicación sea más fácil creamos una vista con Scaffolding.

Una vez creado podremos apreciar que recibimos un model Usuario, el cual no es necesario pasarlo desde el controlador ya que nosotros validaremos de un estado null.

Como habrás comprobar en cada input nos ha creado un binding con la propiedad de Usuario con el atributo de asp-for. Un poco más abajo podemos apreciar como nos pone una etiqueta span con otro asp-for. Esta etiqueta nos mostrará el error en el cada de que lo haya.

¡IMPORTANTE!

Si te fijas bien debajo del todo podemos ver como nos esta incrustando una section Scripts y una carga de unas validaciones parciales. Esto que parece desapercibido es súper importante ya que sin esto las validaciones pierden su magia. Esto permite hacer las validaciones en cliente gracias a nuestro model. De modo que no podremos enviar el formulario hasta todas nuestras validaciones sean correctas.

Autor: Sergio Alcázar Monedero

Curso: Desarrollo Web Full Stack, MultiCloud y Multiplataforma

Centro: Tajamar

Año académico: 2022-2023

Código: https://github.com/sergioalcazar745/MvcNetCoreModelValidation.git

Leave a Comment

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.