martes, 23 de junio de 2015

ASP.NET MVC. ModelValidatorProvider personalizado (y II) - Implementando el Proveedor

Artículo anterior:
ASP.NET MVC. ModelValidatorProvider personalizado (I) - Creando el proyecto de prueba

Tras crear el proyecto de prueba en este artículo vamos a ver cómo crear un proveedor de validadores personalizado de forma que podamos incluir validaciones en función del usuario autenticado en la aplicación.

Para crear el proveedor de validaciones deberemos crear una clase que herede de la clase abstracta System.Web.Mvc.ModelValidatorProvider. Esta clase declara un único método GetValidators que devuelve una lista de objetos ModelValidator.

    // Resumen:
    //     Proporciona una lista de validadores para un modelo.
    public abstract class ModelValidatorProvider
    {
        // Resumen:
        //     Cuando se implementa en una clase derivada, inicializa una nueva instancia
        //     de la clase System.Web.Mvc.ModelValidatorProvider.
        protected ModelValidatorProvider();

        // Resumen:
        //     Obtiene una lista de validadores.
        //
        // Parámetros:
        //   metadata:
        //     Los metadatos.
        //
        //   context:
        //     Contexto.
        //
        // Devuelve:
        //     Lista de validadores.
        public abstract IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context);
    }

Así que voy a crear en una nueva carpeta Infrastructure una nueva clase ValidatorProvider que herede de la clase ModelValidatorProvider.

El objetivo es que el proveedor devuelva una nueva validación para limitar el campo Precio de la clase SolicitudPedido en función del usuario conectado y, si el usuario no es "Jefe", hacer obligatorio el campo Motivo.

Para comprobar si debemos devolver los validadores el método GetValidators recibe dos parámetros:

  • Un objeto ModelMetadata con los metadatos del elemento a validar. Para saber si el elemento a validar se corresponde con las propiedades que buscamos podemos comprobar la propiedad Container que devuelve el objeto al que pertenece la propiedad y que deberá ser del tipo SolicitudPedido, y la propiedad PropertyName que devuelve el nombre de la propiedad a validar.
  • Un objeto ControllerContext con el contexto del controlador. A través de este objeto podremos obtener, por ejemplo, la identidad del usuario actual.
Para crear el validador a devolver cada atributo del namespace DataAnnotations tiene su correspondiente clase con sufijo Adapter que genera el validador a partir de los metadatos del elemento, el objeto de contexto del controlador y una instancia del atributo correspondiente.

using CustomModelValidatorProvider.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;

namespace CustomModelValidatorProvider.Infrastructure
{
    
    public class ValidatorProvider: ModelValidatorProvider
    {
        public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context)
        {
            List<ModelValidator> validators = new List<ModelValidator>();
            if (metadata.Container is SolicitudPedido)
            {
                switch (metadata.PropertyName)
                {
                    case "Precio":
                        double precioMaximo = 100;
                        if (context.HttpContext.User.Identity.Name == "Jefe")
                            precioMaximo = 1000;

                        RangeAttribute range = new RangeAttribute(0.01, precioMaximo);
                        validators.Add(new RangeAttributeAdapter(metadata, context, range));
                        break;
                    case "Motivo":
                        if (context.HttpContext.User.Identity.Name != "Jefe")
                            validators.Add(new RequiredAttributeAdapter(metadata, context, new RequiredAttribute()));
                        break;
                }
            }
            return validators;
        }
    }
}



Por último únicamente quedaría registrar el proveedor en la aplicación. El framework de MVC proporciona una clase estática ModelValidatorProviders con una propiedad Providers que contiene los proveedores de validaciones de la aplicación.

En el evento Application_Start del archivo Global.asax le añadiré una instancia del nuevo proveedor a la colección.

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            RouteConfig.RegisterRoutes(RouteTable.Routes);

            ModelValidatorProviders.Providers.Add(
                new CustomModelValidatorProvider.Infrastructure.ValidatorProvider());
        }

Ahora si arrancamos de nuevo la aplicación podemos comprobar que las validaciones del formulario de solicitud son diferentes dependiendo del usuario con el que nos validemos:

Validaciones del formulario de solicitud

El código

Puedes descargar el código de ejemplo de:


No hay comentarios:

Publicar un comentario