Compartir a través de


Iteración n.º 3: Agregar una validación de formulario (VB)

por Microsoft

Descargar código

En la tercera iteración, añadimos validación básica de formularios. Evitamos que los usuarios envíen un formulario sin completar los campos de formulario obligatorios. También validamos las direcciones de correo electrónico y los números de teléfono.

Creación de una aplicación de ASP.NET MVC de administración de contactos (VB)

En esta serie de tutoriales, creamos una aplicación completa de administración de contactos de principio a fin. La aplicación Contact Manager le permite almacenar información de contacto (nombres, números de teléfono y direcciones de correo electrónico) para obtener una lista de personas.

Compilamos la aplicación en varias iteraciones. Con cada iteración, mejoramos gradualmente la aplicación. El objetivo de este enfoque de iteración múltiple es permitirle comprender el motivo de cada cambio.

  • Iteración n.º 1: Crear la aplicación. En la primera iteración, creamos el Administrador de contactos de la manera más sencilla posible. Agregamos compatibilidad con operaciones básicas de base de datos: Crear, Leer, Actualizar y Eliminar (CRUD).

  • Iteración n.º 2: Hacer que la aplicación tenga un buen aspecto. En esta iteración, mejoramos la apariencia de la aplicación modificando la página maestra de vista predeterminada de ASP.NET MVC y la hoja de estilos en cascada.

  • Iteración n.º 3: Añadir una validación de formulario. En la tercera iteración, añadimos validación básica de formularios. Evitamos que los usuarios envíen un formulario sin completar los campos de formulario obligatorios. También validamos las direcciones de correo electrónico y los números de teléfono.

  • Iteración n.º 4: Hacer que la aplicación tenga un acoplamiento flexible. En esta cuarta iteración, aprovechamos varios patrones de diseño de software para facilitar el mantenimiento y modificación de la aplicación Contact Manager. Por ejemplo, refactorizamos la aplicación para usar el patrón Repositorio y el patrón de inserción de dependencias.

  • Iteración n.º 5: Crear pruebas unitarias. En la quinta iteración, hacemos que la aplicación sea más fácil de mantener y modificar agregando pruebas unitarias. Simulamos nuestras clases de modelo de datos y compilamos pruebas unitarias para nuestros controladores y lógica de validación.

  • Iteración n.º 6: Utilizar el desarrollo mediante pruebas. En esta sexta iteración, añadimos una nueva funcionalidad a nuestra aplicación escribiendo primero pruebas unitarias y escribiendo código en las pruebas unitarias. En esta iteración, agregamos grupos de contactos.

  • Iteración n.º 7: Agregar funcionalidad de Ajax. En la séptima iteración, mejoramos la capacidad de respuesta y el rendimiento de nuestra aplicación agregando compatibilidad con Ajax.

Esta iteración

En esta segunda iteración de la aplicación Contact Manager, agregamos validación básica de formularios. Evitamos que las personas envíen un contacto sin especificar valores para los campos de formulario obligatorios. También validamos números de teléfono y direcciones de correo electrónico (vea la figura 1).

The New Project dialog box

Figura 01: Un formulario con validación (haga clic para ver la imagen a tamaño completo)

En esta iteración, añadimos la lógica de validación directamente a las acciones del controlador. En general, esta no es la manera recomendada de agregar validación a una aplicación ASP.NET MVC. Un enfoque mejor es colocar la lógica de validación de una aplicación en una capa de servicio independiente. En la siguiente iteración, refactorizamos la aplicación Contact Manager para que la aplicación sea más fácil de mantener.

En esta iteración, para simplificar las cosas, se escribe todo el código de validación manualmente. En lugar de escribir el código de validación, podríamos aprovechar un marco de validación. Por ejemplo, puede usar el bloque de aplicación de validación (VAB) de Microsoft Enterprise Library para implementar la lógica de validación de su aplicación ASP.NET MVC. Para más información sobre el bloque de aplicación de validación, consulte:

http://msdn.microsoft.com/library/dd203099.aspx

Añadir validación a la vista Create

Empecemos por añadir lógica de validación a la vista Create. Afortunadamente, como hemos generado la vista Create con Visual Studio, la vista Create ya contiene toda la lógica de interfaz de usuario necesaria para mostrar los mensajes de validación. La vista Create está contenida en la lista 1.

Lista 1: \Views\Contact\Create.aspx

<%@ Page Title="" Language="VB" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage(Of ContactManager.Contact)" %>

<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<title>Create</title>
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

    <%= Html.ValidationSummary() %>

    <% Using Html.BeginForm()%>

        <fieldset>
            <legend>Create New Contact</legend>
            <p>
                <label for="FirstName">First Name:</label>
                <%= Html.TextBox("FirstName") %>
                <%= Html.ValidationMessage("FirstName", "*") %>
            </p>
            <p>
                <label for="LastName">Last Name:</label>
                <%= Html.TextBox("LastName") %>
                <%= Html.ValidationMessage("LastName", "*") %>
            </p>
            <p>
                <label for="Phone">Phone:</label>
                <%= Html.TextBox("Phone") %>
                <%= Html.ValidationMessage("Phone", "*") %>
            </p>
            <p>
                <label for="Email">Email:</label>
                <%= Html.TextBox("Email") %>
                <%= Html.ValidationMessage("Email", "*") %>
            </p>
            <p class="submit">
                <input type="submit" value="Create" />
            </p>
        </fieldset>

    <% End Using %>

</asp:Content>

La clase error de validación de campo se usa para dar estilo a la salida representada por el asistente Html.ValidationMessage(). La clase input-validation-error se usa para dar estilo al cuadro de texto (entrada) representado por el asistente Html.TextBox(). La clase validation-summary-errors se usa para dar estilo a la lista desordenada representada por el asistente Html.ValidationSummary().

Nota:

Puede modificar las clases de hoja de estilos descritas en esta sección para personalizar la apariencia de los mensajes de error de validación.

Añadir lógica de validación a la acción Create

Ahora mismo, la vista Create nunca muestra mensajes de error de validación porque no hemos escrito la lógica para generar ningún mensaje. Para mostrar mensajes de error de validación, debe agregar los mensajes de error a ModelState.

Nota:

El método UpdateModel() agrega mensajes de error a ModelState automáticamente cuando se produce un error al asignar el valor de un campo de formulario a una propiedad. Por ejemplo, si intenta asignar la cadena "apple" a una propiedad BirthDate que acepta valores DateTime, el método UpdateModel() agregará un error a ModelState.

El método Create() modificado de la lista 2 contiene una nueva sección que valida las propiedades de la clase Contact antes de insertar el nuevo contacto en la base de datos.

Lista 2: Controllers\ContactController.vb (crear con validación)

<AcceptVerbs(HttpVerbs.Post)> _
Function Create(<Bind(Exclude:="Id")> ByVal contactToCreate As Contact) As ActionResult
    ' Validation logic
    If contactToCreate.FirstName.Trim().Length = 0 Then
        ModelState.AddModelError("FirstName", "First name is required.")
    End If
    If contactToCreate.LastName.Trim().Length = 0 Then
        ModelState.AddModelError("LastName", "Last name is required.")
    End If
    If (contactToCreate.Phone.Length > 0 AndAlso Not Regex.IsMatch(contactToCreate.Phone, "((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}"))
        ModelState.AddModelError("Phone", "Invalid phone number.")
    End If        
    If (contactToCreate.Email.Length > 0 AndAlso  Not Regex.IsMatch(contactToCreate.Email, "^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$"))
        ModelState.AddModelError("Email", "Invalid email address.")
    End If
    If Not ModelState.IsValid Then
        Return View()
    End If

    ' Database logic
    Try
        _entities.AddToContactSet(contactToCreate)
        _entities.SaveChanges()
        Return RedirectToAction("Index")
    Catch
        Return View()
    End Try
End Function

La sección de validación aplica cuatro reglas de validación distintas:

  • La propiedad FirstName debe tener una longitud superior a cero (y no puede estar formada únicamente por espacios)
  • La propiedad LastName debe tener una longitud superior a cero (y no puede estar formada únicamente por espacios)
  • Si la propiedad Phone tiene un valor (tiene una longitud superior a 0), la propiedad Phone debe coincidir con una expresión regular.
  • Si la propiedad Email tiene un valor (tiene una longitud superior a 0), la propiedad Email debe coincidir con una expresión regular.

Cuando se produce una infracción de las reglas de validación, se agrega un mensaje de error a ModelState con ayuda del método AddModelError(). Cuando agrega un mensaje a ModelState, proporciona el nombre de una propiedad y el texto de un mensaje de error de validación. Este mensaje de error se muestra en la vista mediante los métodos asistentes Html.ValidationSummary() y Html.ValidationMessage().

Una vez ejecutadas las reglas de validación, se comprueba la propiedad IsValid de ModelState. La propiedad IsValid devuelve false cuando se ha agregado algún mensaje de error de validación a ModelState. Si la validación falla, se vuelve a mostrar el formulario Create con los mensajes de error.

Nota:

Obtuve las expresiones regulares para validar el número de teléfono y la dirección de correo electrónico del repositorio de expresiones regulares en http://regexlib.com.

Añadir lógica de validación a la acción Edit

La acción Edit() actualiza un Contacto. La acción Edit() debe realizar exactamente la misma validación que la acción Create(). En lugar de duplicar el mismo código de validación, deberíamos refactorizar el controlador Contact para que tanto las acciones Create() como Edit() llamen al mismo método de validación.

La clase de controlador Contact modificada figura en la lista 3. Esta clase tiene un nuevo método ValidateContact() que se llama dentro de las acciones Create() y Edit().

Lista 3: Controllers\ContactController.vb

Public Class ContactController
    Inherits System.Web.Mvc.Controller

    Private _entities As New ContactManagerDBEntities()

    Protected Sub ValidateContact(contactToValidate As Contact)
        If contactToValidate.FirstName.Trim().Length = 0 Then
            ModelState.AddModelError("FirstName", "First name is required.")
        End If
        If contactToValidate.LastName.Trim().Length = 0 Then
            ModelState.AddModelError("LastName", "Last name is required.")
        End If
        If (contactToValidate.Phone.Length > 0 AndAlso Not Regex.IsMatch(contactToValidate.Phone, "((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}"))
            ModelState.AddModelError("Phone", "Invalid phone number.")
        End If        
        If (contactToValidate.Email.Length > 0 AndAlso  Not Regex.IsMatch(contactToValidate.Email, "^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$"))
            ModelState.AddModelError("Email", "Invalid email address.")
        End If
    End Sub

    '
    ' GET: /Contact

    Function Index() As ActionResult
        Return View(_entities.ContactSet.ToList())
    End Function

    '
    ' GET: /Contact/Create

    Function Create() As ActionResult
        Return View()
    End Function

    '
    ' POST: /Contact/Create

    <AcceptVerbs(HttpVerbs.Post)> _
    Function Create(<Bind(Exclude:="Id")> ByVal contactToCreate As Contact) As ActionResult
        ' Validation logic
        ValidateContact(contactToCreate)
        If Not ModelState.IsValid Then
            Return View()
        End If

        ' Database logic
        Try
            _entities.AddToContactSet(contactToCreate)
            _entities.SaveChanges()
            Return RedirectToAction("Index")
        Catch
            Return View()
        End Try
    End Function

    '
    ' GET: /Contact/Edit/5

    Function Edit(ByVal id As Integer) As ActionResult
        Dim contactToEdit = (from c in _entities.ContactSet _
                           where c.Id = id _
                           select c).FirstOrDefault()

        Return View(contactToEdit)
    End Function

    '
    ' POST: /Contact/Edit/5

    <AcceptVerbs(HttpVerbs.Post)> _
    Function Edit(ByVal contactToEdit As Contact) As ActionResult
        ' Validation logic
        ValidateContact(contactToEdit)
        If Not ModelState.IsValid Then
            Return View()
        End If

        ' Database logic
        Try
            Dim originalContact = (from c in _entities.ContactSet _
                             where c.Id = contactToEdit.Id _
                             select c).FirstOrDefault()
            _entities.ApplyPropertyChanges(originalContact.EntityKey.EntitySetName, contactToEdit)
            _entities.SaveChanges()
            Return RedirectToAction("Index")
        Catch
            Return View()
        End Try
    End Function

    '
    ' GET: /Contact/Delete/5

    Function Delete(ByVal id As Integer) As ActionResult
        Dim contactToDelete = (from c in _entities.ContactSet _
                           where c.Id = id _
                           select c).FirstOrDefault()

        Return View(contactToDelete)
    End Function

    '
    ' POST: /Contact/Delete/5

    <AcceptVerbs(HttpVerbs.Post)> _
    Function Delete(ByVal contactToDelete As Contact) As ActionResult
        Try
            Dim originalContact = (from c in _entities.ContactSet _
                             where c.Id = contactToDelete.Id _
                             select c).FirstOrDefault()
            _entities.DeleteObject(originalContact)
            _entities.SaveChanges()
            Return RedirectToAction("Index")
        Catch
            Return View()
        End Try
    End Function

End Class

Resumen

En esta iteración, hemos agregado la validación básica de formularios a nuestra aplicación Contact Manager. Nuestra lógica de validación impide que los usuarios envíen un nuevo contacto o editen un contacto existente sin proporcionar valores para las propiedades FirstName y LastName. Además, los usuarios deben facilitar números de teléfono y direcciones de correo electrónico válidos.

En esta iteración, hemos agregado la lógica de validación a nuestra aplicación Contact Manager de la forma más sencilla posible. Sin embargo, mezclar nuestra lógica de validación en la lógica de nuestro controlador nos creará problemas a largo plazo. Nuestra aplicación será más difícil de mantener y modificar con el tiempo.

En la próxima iteración, refactorizaremos nuestra lógica de validación y de acceso a la base de datos fuera de nuestros controladores. Aprovecharemos varios principios de diseño de software para permitirnos crear una aplicación más flexible y fácil de mantener.