Introducción al Validation Application Block por Maxi Guillén - Daniel Laco

27. diciembre 2007

 

Enterprise Library Validation Application Block

Uno de los temas siempre mas controversiales en del desarrollo, es el proceso de validación, ya sea en al entrada de datos, en el manejo de las reglas de negocio o en la parte de persistencia de los datos.

Con el Validation Application Block (VAP) contenido en la Enterprise Library podemos resolver de un modo elegante y personalizable toda la problemática de validación en nuestras aplicaciones.

El VAP brinda un entorno común para definir reglas de validación para los objetos del negocio e interfaces de usuario. Facilita varios tipos de clases de validadores que incluyen código para validar tipos de datos de .net. Y pueden desarrollarse validadores personalizados para reutilizar.

Se pueden crear grupos de validadores llamados Rule Set (1 a N validators) mediante parámetros de atributos. Es una forma de validar objetos complejos agrupando validadores de diferentes tipos y aplicándolos a campos, propiedades y a nested objects.

Las validaciones se pueden definir o bien a nivel de atributos en las clases o en un archivo de configuración.


Se puede utilizar con las siguientes tecnologías:
ASP .NET
Windows Forms
Ajax
WCF
WPF Requerimientos:
.Net Framework 2, 3 o 3.5

Para utilizar ValidationBlock no es necesario referenciar toda la Enterpise Library, sólo debemos referenciar las siguientes bibliotecas:
Microsoft.Practices.EnterpriseLibrary.Comon.dll
Microsoft.Practices.EnterpriseLibrary.Validation
Microsoft.Practices.ObjectBuilder.dll
Microsoft.Practices.EnterpriseLibrary.Integration.WinForms (solo en la capa de presentación)

Se utilizan los siguientes name space:
using Microsoft.Practices.EnterpriseLibrary.Validation;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;
using Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WinForms; (solo en la capa de presentación)

Validadores predefinidos
Validation Application Block incluye un conjunto de validadores predefinidos que comúnmente se pueden utilizar en las aplicaciones. Cada validador está asociado a un tipo específico. Algunos de estos validadores son:

  • ContainsCharacterValidator
  • NotNullValidator
  • ObjectValidator
  • DomainValidator
  • StringLengthValidator
Ejemplo de utilización de atributos:
public class Customer
{
    // validator attributes with field as target
    [NotNullValidator]
    [StringLengthValidator(1, 50)]
    public string Name;
 
    // validator attribute with property as target
    [DateRangeValidator("2007-10-27T00:00:00", "2008-10-27T00:00:00")]
    public DateTime DateJoined { get { return this.dateJoined; } }
    
    // validator attribute with method as target
    // assume that ShippingAddress is defined elsewhere and has validation
    [ObjectValidator]
    public ShippingAddress GetPrimaryShippingAddress()    {….}
    // validator attribute with method as target (applied to an enumeration)
    [ObjectCollectionValidator(typeof(ShippingAddress))]
    public IEnumerable<ShippingAddress> GetAlternateShippingAddresses()    {….}
}

Validadores compuestos Se pueden crear Validadores compuestos AND u OR (AndCompositeValidator y OrCompositeValidator), agrupa validaciones en forma lógica, es decir en el caso de And todos los validadores deben devolver verdadero para que el objeto sea válido. Las formas para crear validadores compuestos son:

  • Usar la herramienta de configuración
  • Usar atributos
  • Mediante código

Ejemplo por código:

Validator validator = new AndCompositeValidator(new NotNullValidator(), new StringLengthValidator(4, 8));
string password = "123";
ValidationResults results = validator.Validate(password);
bool esValido = results.IsValid;


Ejemplo por atributos:

public class cliente
{
    private string nombre;
    [ValidatorComposition(CompositionType.And)]
    [NotNullValidator(MessageTemplate = ValidatorMsgs.NotNullMsg), 
     StringLengthValidator(1, 50, MessageTemplate = ValidatorMsgs.StringRange50)]
    public string Nombre
    {
        Get{ return nombre; }
        Set{ nombre = value }
    }
}


Atributos modificadores de validación

Permiten modificar el comportamiento de los atributos de validación. Los atributos modificadores son:

  • ValidatorComposition = [CompositionType.And/CompositionType.Or], permite hacer override del comportamiento por defecto (AND) cuando hay más de un atributo de validación.
  • IgnoreNulls, los demás validadores no serán llamados si el valor que se está verificando es nulo.


Propiedades de los atributos de validación

Property name Description
MessageTemplate Descripcion que aparecerá en la propiedad Message del resultado, si se integra con winforms es lo mostrará el ErrorProvider en la intefaz de usuario.
MessageTemplateResourceName This property defines the name of the resource for message templates.
MessageTemplateResourceType This property defines the name of the type used for the message template resource.
Negate Modifica el comportamiento del validador para que falle la validación si se cumple la condición. Al contrario del comportamiento común que consiste en fallar la validación si no se cumple la condición
Tag Se usa para permitir clasificar los resultados
Ruleset Nombre de la regla a la que pertenece el validador


Ejemplo de uso con una clase:

public partial class Estacion : IDisposable
{
    private int _idEstacion;
    private string _nombre;
        private string _ubicacion;
    private string _telefono;
    private IList<OperacionCabina> _operacionCabinaList;
 
    public int IdEstacion
    {
        get { return this._idEstacion; }
    }
 
    [NotNullValidator(MessageTemplate = ValidatorMsgs.NotNullMsg), 
    StringLengthValidator(1, 50, MessageTemplate = ValidatorMsgs.StringRange50)]
    public string Nombre
    {
        get { return this._nombre; }
        set
        {
            this._nombre = value; 
        }
    }…
 


Validación Self
Consiste en implementar la lógica de validación dentro de la misma clase. Se rotula la clase con [HasSelfValidation] y con [SelfValidation] a cada método de la clase que se llamará cuando se efectúe la validación.

Por ejemplo:

[HasSelfValidation]
public class TemperatureRange
{ 
    private int min; 
    private int max;
 
    // ...
 
    [SelfValidation]             
    public void CheckTemperature(ValidationResults results) 
    { 
         if (max < min) 
           results.AddResult(new ValidationResult("Max less than min", this, null, null, null));
    } 
} 


Si se quiere que la validación sea heredable hay que marcar con HasSelfValidation tanto a la clase padre como a sus hijos y el método de validación debe ser público.


Validación de objetos

Puede realizarse mediante un llamado al método Validate de la clase estática Validation, el resultado se obtiene mediante la clase ValidationResults

Ejemplo de validación de una instancia de la clase Estacion:

Estacion estacion = Global.Data.GetObject<Estacion>();
Validation results = Validation.Validate(estacion);
Bool esValido = results.IsValid;


Puede utilizarse también la clase ValidationFactory para crear una instancia del validador.

Customer myCustomer = new Customer( /* ... */ );
Validator<Customer> goldCustomerValidator =   ValidationFactory.CreateValidator<Customer>("GoldCustomer");
ValidationResults results = goldCustomerValidator.Validate(myCustomer);


Resultados de una validación

El método de validación retornará el resultado en una instancia de la clase ValidationResults que es una colección de objetos ValidationResult los cuales tienen las siguientes propiedades:

Property

Description

Key

Nombre que identifica la ubicación del validador. Ej:”Nombre” significa que se colocó un validador en la propiedad nombre de un objeto Cliente.

Object

Puntero al objeto que fue validado

Message

Describe la falla de la validación

Tag

Valor ingresado por código que describe el resultado, se utilize para clasificar o filtrar

Target

Validador que falló



Herencia

Las reglas de validación se aplican a través de la jerarquía de clases. Si una clase hereda un miembro de de otra y no lo sobrecarga se aplican los validadores de la clase de la cual hereda. Si una clase hereda un miembro y lo sobrecarga, entonces no se aplican las validaciones especificadas en la clase de la cual hereda.

Crear un nuevo validador

Se pueden crear clases validadoras, pueden validar tipos de datos de nuevas formas o pueden validar datos complejos como instancias de la clase Cliente.

Para esto se puede heredar de las clases:

  • Validator<T>, para crear validadores fuertemente tipados.
  • Validator

Crear un nuevo atributo perzonalizado

Se pueden crear atributos personalizados heredando de la clase ValidatorAttribute.

Integración con WinForms
Validation Application Block tiene la capacidad de trabajar en conjunto con el objeto ErrorProvider para mostrar el resultado de las validaciones directamente en los controles con el clásico ícono rojo.
Esto se realiza soltando un control ErrorProvider en el Form deseado y luego soltando un control ValidatorProvider (Que debe ser obtenido partir de la biblioteca de Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WinForms.
Cada control ValidatorProvider que se suelte sobre el formulario adiciona 3 nuevas propiedades para cada control del formulario que pueden ser accedidas desde la grilla de propiedades. Estas propiedades son: PerformValidation, SourcePropertyName y ValidatedProperty.
Para que el formulario valide automáticamente los controles debemos efectuar los siguientes pasos:

  1.  
    1. ErrorProvider: seleccionar el control ErrorProvider deseado del formulario.
    2. Enabled: debe ser igual a True
    3. RulesetName: debe ser igual a la regla deseada si no se utilizó este parámetro en los atributos se puede dejar vacío.
    4. SourceTypeName: Se especifica el camino de namespace hasta la clase contiene las validaciones seguido por el nombre de la biblioteca donde se encuentre.
    5. Ej: SourceTypeName = Entidades.Cliente, Entidades
    6. SpecificationSource: declara desde donde se obtienen las reglas de validación, puede ser desde atributos, archivo de configuración o ambos.
    1. PerformValidation: boleano, true para que el control sea validado con el ErrorProvider.
    2. SourcePropertyName: nombre del campo que tiene definida una validación. Ej. SourcePropertyName=Nombre, si definimos por ejemplo una validación mediante el atributo [NotNullValidator] en la propiedad Nombre de la clase Cliente
    3. ValidatedProperty: nombre de la propiedad del control desde la cual se obtendrá el valor para efectuar la validación. Por ejemplo si el control fuera un TextBox usaríamos ValidatedProperty = Text.
  2. 1. Configurar las propiedades del Control ErrorProvider: 2. Configurar las siguientes propiedades de los controles que se deseen que participen de las validaciones:


Ejemplo de una clase Validator y una clase ValidatorAttribute Personalizado

 [ConfigurationElementType(typeof(CustomValidatorData))]
 public class PercentageValidator: Validator<decimal>
 {
        public PercentageValidator(NameValueCollection attributes) : base(null, null)
        {
        }
 
        public PercentageValidator() : this(null)
        {
        }
 
        protected override void DoValidate(decimal objectToValidate, object currentTarget, 
        string key, ValidationResults validationResults)
        {
            if (objectToValidate < 0 || objectToValidate > 100)
            {
                validationResults.AddResult(new 
                 ValidationResult("El valor debe estar entre 0 y 100.", currentTarget, "Decimal", "", this));
            }
        }
 
        protected override string DefaultMessageTemplate
        {
            get { return "Valor inválido"; }
        }
 }
 
 public class PercentageValidatorAttribute : ValidatorAttribute
 {
        public PercentageValidatorAttribute()
        {
        }
 
        protected override Validator DoCreateValidator(Type targetType)
        {
            return new PercentageValidator();
        }
 }
 
 public class ObjetoTest
 {
        private string nombre;
        private decimal valor;
 
        [PercentageValidator()] //Mi Custom Validator
        public decimal Valor
        {
            get { return valor; }
            set { valor = value; }
        }
 
        [NotNullValidator,StringLengthValidator(1,50)]
        public string Nombre
        {
            get { return nombre; }
            set { nombre = value; }
        }
 }


Como se dijo anteriormente, Application Validation Block permite manejar las reglas de validación mediante el archivo de configuración. El archivo puede ser editado mediante la herramienta “Edit Enterprise Library Configuration”, por ejemplo agregamos una sección de Validation Block y luego se selecciona las clases a validar a partir de ensamblados. Especificamos para cada clase los miembros que serán validados y seleccionamos los Validators deseados y especificamos sus parámetros. También podemos especificar las clases que usen SelfValidation.


Este es un ejemplo de un archivo de configuración, con la definición de validaciones.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="validation" type="Microsoft.Practices./>
      EnterpriseLibrary.Validation.Configuration.
      ValidationSettings,
      Microsoft.Practices.EnterpriseLibrary.Validation"
  </configSections>
  <validation>
    <type name="EntLib3.Subscriber" defaultRule="default">
      <rule name="default">
        <properties>
          <property name="Name">
            <add name="NameNotNull" type="Microsoft.Practices. />
                 EnterpriseLibrary.
                 Validation.Validators.NotNullValidator,
                 Microsoft.Practices.
                 EnterpriseLibrary.Validation"
            <add name="NameLength" type="Microsoft.Practices.
                 EnterpriseLibrary.
                 Validation.Validators.StringLengthValidator,
                 Microsoft.
                 Practices.EnterpriseLibrary.Validation"
                 lowerBound="1"
                 upperBound="200" lowerBoundType="Inclusive"
                 upperBoundType="Inclusive"/>
          </property>
          <property name="EmailAddress">
            <add name="EmailAddressNotNull" type="Microsoft. />
                Practices.
                 EnterpriseLibrary.Validation.Validators.
                 NotNullValidator,
                 Microsoft.Practices.EnterpriseLibrary.
                 Validation"
            <add name="EmailAddressLength" type="Microsoft.
                 Practices.
                 EnterpriseLibrary.Validation.Validators.
                 StringLengthValidator,
                 Microsoft.Practices.EnterpriseLibrary.
                 Validation"
                 lowerBound="1"
                 upperBound="200" lowerBoundType="Inclusive"
                 upperBoundType="Inclusive"/>
          </property>          
        </properties>
      </rule>
    </type>
  </validation>
</configuration>

 

 

.NET ,

Teclas de Acceso Rápido para Visual Studio 2005 por Victor Passador

27. diciembre 2007

 

Atajos de teclado en VS 2005

Aquellos que hayan intentado en algún momento grabar una macro con VS 2003 habrán notado luego que es muy difícil poder asignarle un atajo de teclado (shortcut), casi todas las combinaciones de tecla están ocupadas.

Con VS 2005 la cosa se volvió aún más complicada, y sin bien ya no utilizaremos tantas macros gracias a la aparición de los Code Snippet, con tanta funcionalidad nueva que incorpora la IDE era de esperarse que aparecieran "ocupadas" más combinaciones de tecla (ya veremos lo que nos depara VS2008).

Por esta cuestión de los tiempos modernos, donde justamente uno no tiene tiempo más que para producir, muchas veces no nos tomamos un segundo para estudiar la herramienta con la que pasamos la mayor parte del día, y eso fue lo que hice, me puse a mirar por qué tanta combinación de tecla.

Me aprendí unas cuantas que me permitieron escribir código mucho más rápido que antes y mejorar mucho la productividad.

Quiero compartir las que me parecieron más útiles con 10 ejemplos concretos:

Caso 1: Iniciamos un nuevo proyecto, agregamos algunas carpetas por aquí, algunas clases por allá, las referencias a las dll necesarias, empezamos a escribir las primeras líneas y zás, no tenemos Intellisense porque hemos olvidado alguna sentencia Using al principio.
Solución:
Si conocemos el nombre exacto de la clase, lo escribimos tal cual, aparece el subrayado típico de los "smart tags" de Office sobre la última letra, presionamos "Ctrl + punto" (o "Shift+Alt+F10") se abre el smart tag, le damos Enter y automáticamente se habrá agregado la sentencia Using.

Caso 2:
Estamos declarando una variable dentro de un método, nos damos cuenta que nos conviene declararla como campo privado de la clase en la que estamos y nos gusta declararlas al principio de ésta.
Solución:
Los "bookmarks". Presionamos "Ctrl + K" dos veces y dejaremos una marca en la línea en la que estamos, luego "Ctrl + Home" para ir al principio, declaramos la variable y luego presionando "Ctrl+K, Ctrl+N" iremos a parar al lugar donde habíamos puesto la marca.

Caso 3:
Estamos escribiendo el código de un método, se está volviendo un poco largo y nos gustaría refactorizar para mejorar la legibilidad y aumentar la reutilización.
Solución:
Seleccionamos la porción de código que enviaremos a otro método, presionamos "Ctrl+R, Ctrl+M", se mostrará el cuadro de diálogo de Refactoring pidiendo el nombre del nuevo método, ingresamos, damos Enter y listo.

Caso 4:
¿Quién eligió ese nombre para esa variable/propiedad/método?.
Solución:
Renombremos. "F2" sobre el nombre de la variable, propiedad o método, Refactoring nos va a pedir el nuevo nombre, Enter y se acabó.

Caso 5:
No me gusta como está programado este método, pero no tengo demasiada idea del impacto que ocasionará si meto mano sin buscar.
Solución: "Shif+F12"
sobre el nombre del método y aparecerá la ventanas con todas las referencias a ese método, inclusive la declaración en una Interfaz si fuera el caso. Si hacemos doble click en alguna de esas referencias iremos a parar directamente al código que invoca a nuestro método. Si damos "F12" sobre esa invocación volveremos al código del método en cuestión.

Caso 6:
Quiero ejecutar una prueba sin que se ejecute toda esta porción de código.
Solución:
Seleccionamos las líneas necesarias, presionamos "Ctrl+K, Ctrl+C" y las líneas se comentarán automáticamente (con "Ctrl+K, Ctrl+U" se descomentan). ¡Atención! ¡Sirve también para código HTML y XML!

Caso 7:
Las regiones dejan mucho el código de una clase mucho más prolijo, pero si estamos en una clase grande, buscando algo y no sabemos bien qué, nos la pasaremos expandiendo y colapsando regiones.
Solución:
"Ctrl+M, Ctrl+M", para expandir, y nuevamente la misma combinación para colapsar.

Caso 8:
Seguimos buscando algo en el código, pero vagamente recuerdo como comienza
Solución:
"Ctrl+I" realiza una búsqueda incremental hacia adelante en el código "pintando" la palabra (o parte de esta) que vayamos tipiando. No aparecen ventanas emergentes ni cuadros de diálogo, la búsqueda es en tiempo real sobre el código a medida que se tipea. Si en algún momento completamos la frase a buscar, podemos seguir buscando más apariciones de ese texto con "F3"

Caso 9:
Hay infinidad de documentos abiertos en la IDE, no encuentro el que necesito
Solución:
En realidad dos, con "Ctrl+TAB" podemos ir pasando de un documento a otro. Si mantenemos presionada la tecla "Ctrl" mientra presionamos sucesivamente "TAB", veremos una ventanita similar a la que aparece cuando presionamos "Alt+TAB" para cambiar de aplicación en Windows. La otra solución es presionando "Ctrl+Alt+Flecha abajo", con esto se desplegará en el borde superior derecho del editor de código una lista de los documentos abiertos.

Caso 10:
Toqué código en demasiados lugares de este documento, ¿en qué lugar estaba antes de comenzar?
Solución:
Con "Ctrl+- (Ctrl-menos)" iremos "navegando" hacia atrás por todos los lugares donde pasamos.

Estas combinaciones son solamente las que me parecieron menos conocidas por la mayoría de los desarrolladores y que realmente me permitieron escribir código más eficientemente.

Aquí les dejo una lista recopilada de Internet con muchos más atajos, en una planilla Excel, agrupados en solapas según a que parte de la IDE apliquen, pero ojo, a no confundirse por el tamaño, aunque no lo crean, no están todas.

¡Saludos!

 

Visual Studio