Framework .NET 3.5 08 Validación de datos

35
Validación de datos Introducción a la validación de datos. La validación de datos es el proceso mediante el que nos aseguramos de que los datos manipulados en la aplicación son correctos. Lo cual no solo implica que el tipo de datos sea el adecuado, sino que esté dentro de un rango válido para la aplicación. El 14 de julio de 1789 es una fecha válida, pero difícilmente será la fecha de nacimiento del titular de una cuenta corriente. La mayoría de las validaciones de datos actualmente realizadas son sólo validaciones de entrada de datos, en la introducción de los mismos en la aplicación desde el interfaz de usuario. Este planteamiento, válido hasta ahora, deberá cambiar con el desarrollo por capas, ya que cualquier capa que puede ser cambiada, por lo que ninguna puede asumir que esta validación haya sido efectuada en una capa anterior. Y no sólo en el sentido interfaz -> datos, ya que ¿de dónde vienen los datos que estamos presentando?

Transcript of Framework .NET 3.5 08 Validación de datos

Page 1: Framework .NET 3.5 08 Validación de datos

Validación de datos

Introducción a la validación de datos.La validación de datos es el proceso mediante el que nos

aseguramos de que los datos manipulados en la aplicación son correctos.

Lo cual no solo implica que el tipo de datos sea el adecuado, sino que esté dentro de un rango válido para la aplicación. El 14 de julio de 1789 es una fecha válida, pero difícilmente será la fecha de nacimiento del titular de una cuenta corriente.

La mayoría de las validaciones de datos actualmente realizadas son sólo validaciones de entrada de datos, en la introducción de los mismos en la aplicación desde el interfaz de usuario.

Este planteamiento, válido hasta ahora, deberá cambiar con el desarrollo por capas, ya que cualquier capa que puede ser cambiada, por lo que ninguna puede asumir que esta validación haya sido efectuada en una capa anterior. Y no sólo en el sentido interfaz -> datos, ya que ¿de dónde vienen los datos que estamos presentando?

Page 2: Framework .NET 3.5 08 Validación de datos

Validación de datos

Introducción a la validación de datos (II).Este planteamiento se integra dentro de las políticas de seguridad

ya que un escenario habitual es el de un hacker probando hasta donde llega la validación de datos y aprovechando los huecos para introducir código malicioso.

Hay diferentes técnicas de validación, pero es recomendable validar la corrección de los datos en lugar de intentar comprobar si los valores son erróneos.

Normalmente las pruebas que realizamos no detectan todos los errores de validación ya que están orientadas a validar funcionalidades y no inconsistencias de datos. Por lo que es recomendable diseñar las pruebas teniendo esto en mente y añadir validación integral de datos como parte del proceso de prueba.

La mayoría de desarrolladores no pensamos en los ataques maliciosos que puedan lanzarse con nuestras aplicaciones cuando las estamos probando, circunstancia obviamente aprovechada por los hackers en cuanto les damos la oportunidad.

¡Acordémonos de validar los rangos de los datos, no sólo su tipo!

Page 3: Framework .NET 3.5 08 Validación de datos

Validación de datos

Introducción a la validación de datos (III).Ya se ha comentado que actualmente la validación de datos la

efectuamos sólo en la capa de presentación, pero debemos realizarla en cada capa, ya que cuando diseñamos y desarrollamos la aplicación, no somos capaces de prever todos los usos que nuestra aplicación o módulo tendrán en un futuro.

En cada capa se presentan necesidades de validación ya que no podemos esperar que la capa anterior haya realizado todas las validaciones pertinentes. Aunque inicialmente seamos nosotros o nuestro equipo los que desarrollen las capas adyacentes y tengamos claro el diseño de las mismas, en un futuro cualquiera de estas capas puede ser cambiada por otros desarrollos que no tengan el mismo detalle de diseño que las iniciales, con lo que podrían entrar datos incorrectos en nuestros procesos. Y no sólo en cuanto a la persistencia de los datos, a pesar de ser en esta capa donde mayor importancia cobra la validación de los datos a almacenar, no debiendo confiarse sólo en las validaciones que hayan podido efectuarse en la capa de presentación y/o las modificaciones aportadas en la capa de negocio.

Page 4: Framework .NET 3.5 08 Validación de datos

Validación de datos

Introducción a la validación de datos (IV).Las técnicas de validación cambian según el tipos de dato, amén de las que realice el sistema en función del tipo de dato:

Números: tamaño de la variable, el signo, la presencia de decimales y el rango.Cadenas: tamaño máximo y mínimo, la codificación (UTF-8/UTF-16), la presencia de caracteres especiales.Nombres de archivo: que sea una cadena, que sea un nombre archivo válido, que no contenga comodines.URL o URI: similares a los nombres de archivo.Archivos de entrada: a las de nombres de archivo se añadirá el validar si la fuente es de confianza, el formato del archivo, si es texto o binario, el contenido, la codificación, etc.Fechas: aunque se presenten como texto, las fechas son realmente números, pero los formatos de entrada son altamente sensibles a la cultura específica del cliente, el uso de los controles calendar, en lugar de TextBox, es altamente recomendable. El rango de las fechas es otra cosa a tener muy en cuenta.Clases: las específicas en cada caso.

Las expresiones regulares (RegEx) son una herramienta muy poderosa y eficiente a la hora de procesar y validar texto.

Page 5: Framework .NET 3.5 08 Validación de datos

Validación de datos

Validar aplicaciones Windows Forms – eventos de validación.

La validación de un formulario Windows puede ser efectuada a dos niveles:

Implícitamente: al nivel de control individual, especialmente útil cuando la validación de un control dependa de otra, aunque puede condicionar la secuencia de cumplimentación del formulario.Explícitamente: al nivel de formulario, al pulsar el botón de pasar adelante, útil si el orden de relleno de los campos no es importante y se quieren efectuar las validaciones por código y en bloque.Ambas técnicas pueden combinarse, en función de las

necesidades.La mayoría de los controles de Windows Forms tienen un evento

de validación, el cual se lanza cuando el usuario intenta salir del control y el mismo tiene su propiedad CausesValidation en true. Podemos añadir código al evento para implementar dicha validación o utilizar las validaciones del propio control.

Los controles asociados a datos también tienen eventos de validación para asegurar la calidad del dato almacenado.

Page 6: Framework .NET 3.5 08 Validación de datos

Validación de datos

Validar aplicaciones Windows Forms– Control MaskedTextBox.

Este control está específicamente diseñado para poder efectuar validaciones de cadenas de caracteres sin tener que añadir código en el evento, mediante el uso de máscaras de edición para el texto para efectuar los siguientes tipos de validación:

Caracteres requeridos.

Caracteres opcionales.

El tipo de dato esperado en determinada posición de la cadena.

Los caracteres que deban aparecer en posiciones fijas (guiones,

comas, …)

Procesos especiales a aplicar a la cadena, por ejemplo la

conversión automática a mayúsculas.

Cadenas literales predefinidas incluidas dentro del texto a rellenar,

que el control devolverá junto con lo introducido por el cliente.

Page 7: Framework .NET 3.5 08 Validación de datos

Validación de datos

Validar aplicaciones Windows Forms – Omisión y retorno.Algunas veces las validaciones han de ser omitidas, por ejemplo al

cerrar un formulario. Para ello utilizaremos el evento FormClosing del formulario y pondremos la propiedad e.cancel a false.Retorno (feedback)

El efectuar las validaciones a distintos niveles añade complejidad ya que ¿cómo se informa al usuario de los errores?

En la capa de presentación: es fácil, ya que estamos interactuando con el usuario y disponemos de varios mecanismos.En la capa de negocio: aquí la cosa se complica, ya que no hay interacción directa con el usuario y, además, desconocemos cuál es el tipo de interfaz utilizado. Aunque tenemos un par de mecanismos para solventar este problema:

Generar códigos de retorno e información adicional para que el código cliente lo recupera y presente como sea necesario.Lanzar una excepción para que sea recogida desde el código cliente.

En la capa de datos: nos encontramos con la misma situación que en el caso anterior, pudiendo lanzarse o sólo registrarse y devolver un código de retorno de error.

Page 8: Framework .NET 3.5 08 Validación de datos

Validación de datos

Validar aplicaciones Windows Forms - Demostración.En esta demostración veremos la codificación y el funcionamiento

de las validaciones implícitas y explícitas en formularios Windows.

Utilizaremos la validación implícita con eventos de validación.

Usaremos un evento FormClosing para cancelar la validación al cerrar el formulario.

Efectuaremos validaciones explícitas.

Utilizaremos el control MaskedTextBox.

Efectuaremos validaciones en la capa intermedia.

Evidentemente, para poder efectuar estas validaciones será necesario tener algo de código desarrollado y funcionalidades que aún no han sido introducidas, el objetivo es el de ver en acción las validaciones de Windows Forms, no el de explicar la tecnologías adicionales aquí utilizadas.

La solución que utilizaremos es la DemoValidaciónWF.

Page 9: Framework .NET 3.5 08 Validación de datos

Validación de datos

Validar aplicaciones ASP.NETEn las aplicaciones ASP.NET es necesario tomar una decisión importante

a la hora de enfocar el diseño de las mismas: ¿Dónde queremos efectuar las validaciones? ¿En el cliente o en el servidor?

En la parte cliente, se realizará mediante el uso del lenguaje JavaScript, para que las validaciones se realicen directamente desde el propio browser del usuario, sin necesidad de envíos y respuestas al servidor. Sus principales características son:

Ligero y rápido.Requiere un desarrollador experto en JavaScript.El código de validación está abierto para que cualquiera lo vea, aunque lo encriptemos, ya que es fácil de saltar.Si se han de validar datos contra listas de valores, estas deberán residir en la página o en una fuente externa descargada junto con la misma.

En la parte servidor, como su nombre indica, las validaciones las realizaremos en el servidor. Sus principales características son:

Requiere el envío de la página al servidor para su validación.El estado de los controles debe ser transferido en ambos sentidos, para mantener el estado de la página (viewstate)El cliente no puede ver el código de validación y éste se desarrollará con las mismas herramientas que el resto de la aplicación.Al ejecutarse el código en el servidor, las validaciones complejas o contra base de datos se pueden realizar sin ningún problema.

Page 10: Framework .NET 3.5 08 Validación de datos

Validación de datos

Validar aplicaciones ASP.NET (II) - ValidadoresEstos son controles incluidos en Visual Studio 2008 y que se

utilizan para la validación de datos en ASP.NET, tanto en la parte cliente como en la del servidor.

Están asociados a otro control (ControlToValidate) y permiten indicar el tipo de validación que se ha de efectuar sobre éste primero.

Los controles validadores son:RequiredFieldValidator: permite garantizar que el campo no está en blanco ni vacío.CompareValidator: permite comparar los valores de dos controles relacionados.RangeValidator: valida que el valor del campo esté en un rango.RegularExpressionValidator: permite efectuar la validación con una expresión regular, con toda la potencia que éstas tienen.CustomValidator: nos permite codificar nuestra propia validación, si las anteriores no nos satisfacen.ValidationSummary: es un resumen de las validaciones efectuadas.DynamicValidator: recoge las excepciones lanzadas desde el modelo de datos y las replica como eventos de validación en la página Web.

Page 11: Framework .NET 3.5 08 Validación de datos

Validación de datos

Validar aplicaciones ASP.NET (III) - DemostraciónEn esta demostración veremos las validaciones típicas en las

aplicaciones Web de ASP.NET, mediante el uso de los controles validadores:

RequiredFieldValidator.

RangeValidator.

RegularExpressionValidator.

CustomValidatorControl.

ValidationSummary.

Como en la demostración anterior, no se trata aquí de ver a fondo todo el código desarrollado, sólo remarcar el uso de las validaciones en ASP.NET, el resto del código y sus particularidades se verán más adelante.

La solución que utilizaremos es la DemoValidaciónASP.

Page 12: Framework .NET 3.5 08 Validación de datos

Validación de datos

Manejo de texto y cadenas largasAl desarrollar aplicaciones nos encontraremos con la necesidad de

procesar textos, para lo cual el Framework nos da herramientas para leer, almacenar y manipular cadenas de caracteres mediante String y StringBuilder, expresiones regulares (RegEx) y las páginas de códigos.

Las características de la clase String son:Es una colección de caracteres Unicode.Implementada como un array de objetos Char.El valor del objeto String es el contenido de la colección.Es un tipo por referencia.

Permite:Especificar reglas de formato para manejar el contenido.Operaciones sensibles a cultura para manejar la presentación del contenido.Efectuar búsquedas y sustituciones de sub-cadenas.Concatenar múltiples cadenas en una.Trocear cadenas largas en varias pequeñas.

Todos los tipos de .NET tiene un método ToString, heredado de la clase Object, para generar un String con su contenido.

Page 13: Framework .NET 3.5 08 Validación de datos

Validación de datos

Manejo de texto y cadenas largas (II) – Métodos de String

Método Ámbito DescripciónClone Instancia Devuelve una nueva referencia al objeto String.

Compare Clase Compara dos objetos String y devuelve el resultado.

CompareTo Instancia Compara esta instancia con un objeto específico y devuelve la posición en la que ha hallado la cadena en el objeto.

Concat Clase Concatena dos o más instancias de String en un nuevo objeto String.

Contains Instancia Devuelve un valor booleano indicando si la instancia contiene determinada cadena de caracteres.

Copy Clase Crea un nuevo objeto String con el mismo contenido.

EndsWith Instancia Devuelve un valor booleano indicando si el objeto acaba con la cadena indicada.

Equals Ambos Determina si dos String tienen el mismo contenido.

Format Clase Construye una nueva cadena sustituyendo cada item del format con un nuevo valor

Insert Instancia Devuelve un nuevo String con la cadena pasada insertada en la posición indicada de la instancia.

Page 14: Framework .NET 3.5 08 Validación de datos

Validación de datos

Manejo de texto y cadenas largas (III) – Métodos de String

Método Ámbito DescripciónJoin Clase Devuelve un nuevo String con la concatenación de todos

los elementos de un Array, añadiendo el separador indicado.

Remove Instancia Devuelve un nuevo String con la cadena limpia de los elementos indicados.

Replace Instancia Devuelve un nuevo String con una sub-cadena sustituida por otra específica, en todas sus apariciones.

Split Instancia Devuelve un Array de String con la cadena original segmentada según lo indicado.

StartsWith Instancia Devuelve un valor booleano indicado si la cadena empieza con una determinada sub-cadena

ToCharArray Instancia Devuelve el contenido del String como un nuevo Array de Char.

Trim Instancia Elimina todas las apariciones de determinado carácter al inicio y/o fin de la cadena

Page 15: Framework .NET 3.5 08 Validación de datos

Validación de datos

Manejo de texto y cadenas largas (IV) – Miembros de String

Miembro Ámbito Tipo DescripciónEquality Clase Operad

orDetermina si dos Sring tienen el mismo contenido

IndexOf Instancia Propiedad de índice

Devuelve un entero con la posición inicial de una sub-cadena

Inequality Clase Operador

Determiona si dos String difieren en su contenido

Empty Clase Campo Representa una cadena vacía

Chars Instancia Propiedad de índice

Devuelve el carácter en determinada posición.

LastIndexOf Instancia Propiedad de índice

Devuelve un entero con la posición de la última aparición de una sub/cadena

Length Instancia Propiedad

Devuelve el número de caracteres en la instancia.

Page 16: Framework .NET 3.5 08 Validación de datos

Validación de datos

Manejo de texto y cadenas largas (V)

Un objeto String es inmutable, es decir:Después de creado, no se puede modificar.Cualquier método que parece cambiar el String está devolviendo realmente un nuevo String, con el contenido cambiado.Para modificar el contenido es preciso utilizar la clase System.text.StringBuilder

Esta clase:Representa una cadena de caracteres modificable.Se puede concatenar, eliminar, sustituir e insertar caracteres sin crear un nuevo objeto.La longitud máxima de 2.147.483.647 caracteres (Int.MaxValue).El tamaño inicial por defecto es de 16 caracteres, pero esta clase se expande dinámicamente al añadir contenido.El método ToString() devuelve el contenido completo del objeto StringBuilder como un String.

Page 17: Framework .NET 3.5 08 Validación de datos

Validación de datos

Manejo de texto y cadenas largas (VI) – Miembros de StringBuilder

Miembro Tipo DescripciónCapacity Propieda

dRecupera o fija el máximo de caracteres

Chars Propiedad

Recupera o fija el carácter en una determinada posición

Length Propiedad

Recupera o fija el número de caracteres almacenados

Append Método Añade la representación en String de un determinado objeto al final del contenido de la instancia.

AppendFormat Método Añade un String formateado al final del contenido actual.

EnsureCapacity

Método Se asegura de que el objeto admita el tamaño indicado, ampliándose si es necesario.

Insert Método Inserta la representación en String de un objeto en la posición indicada de contenido actual.

Remove Método Elimina un determinado número de caracteres á partir de una posición dada

Replace Método Sustituye una sub-cadena por otra dada, en todas sus apariciones.

Page 18: Framework .NET 3.5 08 Validación de datos

Validación de datos

C#StringBuilder cadena = new StringBuilder();cadena.Append(“Primera parte de la cadena.”);cadena.AppendFormat(“{0} y {1} partes de la cadena.”, “Segunda”, “tercera”);

VBDim cadena as New StringBuilder()cadena.Append(“Primera parte de la cadena.”)cadena.AppendFormat(“ {0} y {1} partes de la cadena.”, _ “Segunda”, “tercera”)

Manejo de texto y cadenas largas (VII)Cómo usar StringBuilder

Resultado:"Primera parte de la cadena. Segunda y tercera partes de la cadena."

Page 19: Framework .NET 3.5 08 Validación de datos

Validación de datos

Expresiones regulares

Además de las operaciones de manipulación de cadenas vistas hasta ahora, en algunas ocasiones es necesario procesar la información contenida en las cadenas de caracteres o realizar validaciones sobre la misma.Por ejemplo, podríamos querer limitar el tipo de caracteres utilizados en un campo de contraseña introducido por el usuario, en cuanto a que deban o no contener caracteres especiales, mayúsculas, minúsculas y/o números.También es posible que tengamos que lidiar con información suministrada por un sistema antiguo, cuyo formato no sea totalmente compatible con los sistemas actuales.Estos requerimientos son bastante complejos de gestionar mediante código y requieren un montón de instrucciones para ello.Pero disponemos de las expresiones regulares (RegEx), desarrollados en los entornos UNIX y PERL durante décadas, las cuales son laboriosas de entender, pero extremadamente eficaces a la hora de realizar este tipo de operaciones.

Page 20: Framework .NET 3.5 08 Validación de datos

Validación de datos

Expresiones regulares (II)

Una expresión regular es una secuencia de caracteres (pattern string) con la que se puede:

Comparar con un String para comprobar requerimientos de formato.Utilizar para sustituir o eliminar datos de una cadena.Comparar con apariciones repetitivas de datos.Utilizar para cambiar el formato de los datos o eliminar caracteres no válidos.

Las expresiones regulares pueden ser extremadamente complejasLa mayoría de los caracteres especiales son sensibles al contexto y tienen múltiples usos.Las expresiones regulares no tienen contexto de datos, habremos de gestionarlo nosotros en caso necesario.Un solo carácter erróneo en la expresión puede inutilizarla toda o producir resultados absolutamente aleatorios.

Page 21: Framework .NET 3.5 08 Validación de datos

Validación de datos

Expresiones regulares (III)

^\S{3}-?\d{4}$Desde el inicio

Hasta el final

Cualquier carácter no

vacío ni espacio

El carácter anterior n

veces

Cualquier dígito

numérico

El carácter anterior

es opcional

El carácter anterior n

veces

Válido No válido Explicación

ABC-1234 ABC 1234 El espacio en blanco

DEF-5678 DEF1-234 Cuatro caracteres antes del guión

Def-3856 D f-3856 Espacio en grupo sin espacios

Gru7589 G.U 7589 Punto en grupo y espacio

Gln-6577 GlN--6577 Dos guiones

Page 22: Framework .NET 3.5 08 Validación de datos

Validación de datos

Expresiones regulares (IV)

Page 23: Framework .NET 3.5 08 Validación de datos

Validación de datos

Expresiones regulares (V)

Page 24: Framework .NET 3.5 08 Validación de datos

Validación de datos

Expresiones regulares (VI)

Page 25: Framework .NET 3.5 08 Validación de datos

Validación de datos

Expresiones regulares (VII)

Page 26: Framework .NET 3.5 08 Validación de datos

Validación de datos

Expresiones regulares (VIII)

Page 27: Framework .NET 3.5 08 Validación de datos

Validación de datos

Expresiones regulares (IX)

Page 28: Framework .NET 3.5 08 Validación de datos

Validación de datos

Expresiones regulares (X)

Page 29: Framework .NET 3.5 08 Validación de datos

Validación de datos

Expresiones regulares (XI)

Page 30: Framework .NET 3.5 08 Validación de datos

Validación de datos

Expresiones regulares (XII)

Para utilizar expresiones regulares para validar cadenas deberemos:Crear un objeto Regex, pasándole la plantilla de caracteres a utilizar como parámetro del constructor.Llamar a los métodos Ismatch, Match o Matches del objeto Regex, pasándole la cadena a validar como parámetro.

Si queremos utilizar los métodos estáticos de la clase Regex deberemos llamar a los métodos Regex.IsMatch, Regex.Match o Regex.Matches pasando la plantilla y la cadena a validar contra ella como parámetros.

Page 31: Framework .NET 3.5 08 Validación de datos

Validación de datos

Expresiones regulares (XIII)

Para utilizar expresiones regulares para extraer datos de cadenas deberemos:Crear una expresión regular que incluya grupos de coincidencia.Crear un objeto Regex.Crear una instancia del objeto Match utilizando el método instance.MatchRecuperar los datos accediendo a los miembrs de la colección Match.Groups.

Si queremos utilizar los métodos estáticos deberemos efectuar lo mismo que arriba, ignorando el segundo paso y llamando a Regex.Match en el paso 3.

Page 32: Framework .NET 3.5 08 Validación de datos

Validación de datos

Codificación de texto

Las páginas de código son los juegos de caracteres utilizados para representar datos de cadena.

Todos los tipos de codificación siguen basados en las tablas ASCII, las cuales utilizan 7 bits para representar los caracteres, lo cual nos da 128 caracteres.

Muchos fabricantes utilizan los valores restantes, del 128 al 255, pero cada uno utiliza un formato propio, lo cual desemboca en incompatibilidades de codificación.

Esta situación forzó la adopción de las páginas de códigos estándar de ANSI llamadas Unicode, las cuales nos permiten unos 100.000 caracteres distintos en una única página.

Page 33: Framework .NET 3.5 08 Validación de datos

Validación de datos

Codificación de texto (II)

La clase Encoding es la que nos suministra el sistema para lidiar con estas temas y tiene métodos para:

Devolver y tipo de codificación para poder codificar textos.

Convertir una cadena de entrada en una serie de bytes de un determinado código.

Suministrar soporte para una amplia variedad de codificaciones ANSI e ISO.

El método Encoding.GetBytes es que se utiliza para la conversión de cadenas.

Dim e as Encoding = Encoding.GetEncoding("Korean")

Dim EncodedString As Byte()

EncodedString = e.GetBytes("¡Hola, mundo!“)

[VB] [VB]

Encoding e = Encoding.GetEncoding("Korean")

Byte[] EncodedString;

EncodedString = e.GetBytes("¡Hola, mundo!");

[C#[C#

Page 34: Framework .NET 3.5 08 Validación de datos

Validación de datos

Preguntas:¿Qué es la validación de datos?Es el proceso de asegurar que los datos de la aplicación son

correctos y están dentro de los rangos adecuados.¿En que se diferencia la validación de datos de la de entrada de

datos?La validación de entrada de datos se efectúa en la capa de

presentación, en el momento en el que se efectúa introducción de información en el sistema. En cambio la validación de datos se efectúa en cualquier capa de la aplicación y se asegura que la información manejada es adecuada para el sistema.

¿Porqué es importante realizar validaciones en cada capa?Porque las aplicaciones se desarrollan cada vez más en forma

modular, sin depender unas capas de otras, lo cual implica que no podemos confiar en que las validaciones hayan sido efectuadas en una capa anterior.

Page 35: Framework .NET 3.5 08 Validación de datos

Validación de datos

Preguntas:¿Cuál es la diferencia entre validación implícita y explícita?La validación implícita se realiza control a control, pero la explícita

se realiza a nivel de formulario, mediante una rutina llamada al pulsar un botón de acción.

¿Se puede utilizar la funcionalidad y sencillez de los validadores en el lado del cliente?

Si, fijando la propiedad client-side validation a true.¿En qué forma nos ayuda el control MaskedTextBox para la

validación de datos?En que nos permite filtrar los datos introducidos siguiendo una

plantilla establecida. ¿Cómo podemos evitar que se efectúen las validaciones por

defecto al cerrar el formulario?Fijando la propiedad cancel a false en el evento form closing.