Compartir vía


Agregar la validación al modelo (VB)

Por Rick Anderson

Este tutorial le enseñará los conceptos básicos para crear una aplicación web de ASP.NET MVC mediante Microsoft Visual Web Developer 2010 Express Service Pack 1, que es una versión gratuita de Microsoft Visual Studio. Antes de empezar, asegúrese de que ha instalado los requisitos previos que se enumeran a continuación. Para instalarlos todos, haga clic en el vínculo siguiente: Instalador de plataforma web. Como alternativa, puede instalar individualmente los requisitos previos mediante los vínculos siguientes:

Si usa Visual Studio 2010 en lugar de Visual Web Developer 2010, instale los requisitos previos haciendo clic en el vínculo siguiente: Requisitos previos de Visual Studio 2010.

Un proyecto de Visual Web Developer con código fuente VB.NET está disponible para acompañar este tema. Descargue la versión de VB.NET. Si prefiere C#, cambie a la versión de C# de este tutorial.

En esta sección, agregará lógica de validación al modelo Movie y garantizará que las reglas de validación se apliquen cada vez que un usuario intente crear o editar una película mediante la aplicación.

Respeto del principio DRY

Uno de los principales principios de diseño de ASP.NET MVC es DRY ("Una vez y solo una"). ASP.NET MVC le anima a que especifique la funcionalidad o el comportamiento una sola vez y luego lo refleje en el resto de la aplicación. Esto reduce la cantidad de código que necesita escribir y hace que el código que escribe sea mucho más fácil de mantener.

La compatibilidad de validación proporcionada por ASP.NET MVC y Code First de Entity Framework es un buen ejemplo del principio DRY en acción. Puede especificar las reglas de validación mediante declaración en un lugar (en la clase del modelo) y esas reglas se aplican en toda la aplicación.

Ahora verá cómo puede aprovechar esta compatibilidad de validación en la aplicación de películas.

Adición de reglas de validación al modelo Movie

Comenzará agregando alguna lógica de validación a la clase Movie.

Abra el archivo Movie.vb. Agregue una instrucción Imports en la parte superior del archivo que haga referencia al espacio de nombres System.ComponentModel.DataAnnotations:

Imports System.ComponentModel.DataAnnotations

El espacio de nombres forma parte de .NET Framework. Proporciona un conjunto integrado de atributos de validación que se aplican mediante declaración a cualquier clase o propiedad.

Ahora, actualice la clase Movie para aprovechar las ventajas de los atributos de validación integrados Required, StringLength y Range. Use el código siguiente como ejemplo de dónde aplicar los atributos.

Public Class Movie
    Public Property ID() As Integer

    <Required(ErrorMessage:="Title is required")>
    Public Property Title() As String

    <Required(ErrorMessage:="Date is required")>
    Public Property ReleaseDate() As Date

    <Required(ErrorMessage:="Genre must be specified")>
    Public Property Genre() As String

    <Required(ErrorMessage:="Price Required"), Range(1, 100, ErrorMessage:="Price must be between $1 and $100")>
    Public Property Price() As Decimal

    <StringLength(5)>
    Public Property Rating() As String
End Class

Los atributos de validación especifican el comportamiento que quiere aplicar en las propiedades del modelo al que se aplican. El atributo Required indica que una propiedad debe tener un valor; en este ejemplo, una película debe tener valores para las propiedades Title, ReleaseDate, Genre y Price para que sea válida. El atributo Range restringe un valor a un intervalo determinado. El atributo StringLength permite establecer la longitud máxima de una propiedad de cadena y, opcionalmente, su longitud mínima.

Code First garantiza que las reglas de validación que especifique en una clase de modelo se aplican antes de que la aplicación guarde los cambios en la base de datos. Por ejemplo, el código siguiente iniciará una excepción cuando se llame al método SaveChanges, ya que faltan varios valores de propiedad Movie obligatorios y el precio es cero (que está fuera del intervalo válido).

Dim db As New MovieDBContext()

Dim movie As New Movie()
movie.Title = "Gone with the Wind"
movie.Price = 0.0D

db.Movies.Add(movie)
db.SaveChanges() ' <= Will throw validation exception

Tener reglas de validación aplicadas automáticamente por .NET Framework ayuda a que la aplicación sea más sólida. También nos permite asegurarnos de que todo se valida y que no nos dejamos ningún dato incorrecto en la base de datos accidentalmente.

Esta es una lista de código completa para el archivo de Movie.vb actualizado:

Imports System.Data.Entity
Imports System.ComponentModel.DataAnnotations

Public Class Movie
    Public Property ID() As Integer

    <Required(ErrorMessage:="Title is required")>
    Public Property Title() As String

    <Required(ErrorMessage:="Date is required")>
    Public Property ReleaseDate() As Date

    <Required(ErrorMessage:="Genre must be specified")>
    Public Property Genre() As String

    <Required(ErrorMessage:="Price Required"), Range(1, 100, ErrorMessage:="Price must be between $1 and $100")>
    Public Property Price() As Decimal

    <StringLength(5)>
    Public Property Rating() As String
End Class

Public Class MovieDBContext
    Inherits DbContext
    Public Property Movies() As DbSet(Of Movie)
End Class

Interfaz de usuario de error de validación en ASP.NET MVC

Vuelva a ejecutar la aplicación y vaya a la dirección URL /Movies.

Haga clic en el vínculo Crear película para agregar una nueva película. Rellene el formulario con algunos valores no válidos y, después, haga clic en el botón Crear.

8_validationErrors

Observe cómo el formulario ha usado automáticamente un color de fondo para resaltar los cuadros de texto que contienen datos no válidos y ha emitido un mensaje de error de validación adecuado junto a cada uno. Los mensajes de error coinciden con las cadenas de error que ha especificado al anotar la clase Movie. Los errores se aplican en el lado cliente (con JavaScript) y en el lado servidor (cuando un usuario tiene JavaScript deshabilitado).

Una ventaja importante es que no fue necesario cambiar ni una sola línea de código en la clase MoviesController o en la vista Create.vbhtml para habilitar esta interfaz de usuario de validación. El controlador y las vistas que creó en pasos anteriores de este tutorial seleccionaron automáticamente las reglas de validación que especificó mediante atributos en la clase del modelo Movie.

Cómo se produce la validación en la vista Create y el método de acción Create

Tal vez se pregunte cómo se generó la validación de la interfaz de usuario sin actualizar el código en el controlador o las vistas. En la lista siguiente se muestra el aspecto de los métodos Create de la clase MovieController. No han cambiado de la forma en que los ha creado antes en este tutorial.

'
' GET: /Movies/Create

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

'
' POST: /Movies/Create

<HttpPost()>
Function Create(movie As Movie) As ActionResult
    If ModelState.IsValid Then
        db.Movies.Add(movie)
        db.SaveChanges()
        Return RedirectToAction("Index")
    End If

    Return View(movie)
End Function

El primer método de acción muestra el formulario Create inicial. El segundo controla la publicación del formulario. El segundo método Create llama a ModelState.IsValid para comprobar si la película tiene errores de validación. Al llamar a este método se evalúan todos los atributos de validación que se hayan aplicado al objeto. Si el objeto tiene errores de validación, el método Create vuelve a mostrar el formulario. Si no hay ningún error, el método guarda la nueva película en la base de datos.

Abajo se muestra la plantilla de vista Create.cshtml a la que se aplicó scaffolding en un paso anterior de este tutorial. Los métodos de acción que se muestran arriba la usan para mostrar el formulario inicial y para volver a mostrarlo en caso de error.

@ModelType MvcMovie.Movie

@Code
    ViewData("Title") = "Create"
End Code

<h2>Create</h2>

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

@Using Html.BeginForm()
    @Html.ValidationSummary(True)
    @<fieldset>
        <legend>Movie</legend>

        <div class="editor-label">
            @Html.LabelFor(Function(model) model.Title)
        </div>
        <div class="editor-field">
            @Html.EditorFor(Function(model) model.Title)
            @Html.ValidationMessageFor(Function(model) model.Title)
        </div>

        <div class="editor-label">
            @Html.LabelFor(Function(model) model.ReleaseDate)
        </div>
        <div class="editor-field">
            @Html.EditorFor(Function(model) model.ReleaseDate)
            @Html.ValidationMessageFor(Function(model) model.ReleaseDate)
        </div>

        <div class="editor-label">
            @Html.LabelFor(Function(model) model.Genre)
        </div>
        <div class="editor-field">
            @Html.EditorFor(Function(model) model.Genre)
            @Html.ValidationMessageFor(Function(model) model.Genre)
        </div>

        <div class="editor-label">
            @Html.LabelFor(Function(model) model.Price)
        </div>
        <div class="editor-field">
            @Html.EditorFor(Function(model) model.Price)
            @Html.ValidationMessageFor(Function(model) model.Price)
        </div>

 <div class="editor-label">
     @Html.LabelFor(Function(model) model.Rating)
 </div>
 <div class="editor-field">
     @Html.EditorFor(Function(model) model.Rating)
     @Html.ValidationMessageFor(Function(model) model.Rating)
 </div>

        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
End Using

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

Observe cómo el código usa un asistente Html.EditorFor para generar el elemento <input> para cada propiedad Movie. Junto a este asistente, se llama al método asistente Html.ValidationMessageFor. Estos dos métodos de asistente funcionan con el objeto de modelo que pasa el controlador a la vista (en este caso, un objeto Movie). Buscan automáticamente los atributos de validación especificados en el modelo y muestran los mensajes de error según corresponda.

Lo mejor de este enfoque es que ni el controlador ni la plantilla de vista Create saben nada de las reglas de validación actuales que se aplican, ni conocen los mensajes de error específicos que se muestran. Las reglas de validación y las cadenas de error solo se especifican en la clase Movie.

Si quiere cambiar la lógica de validación más adelante, puede hacerlo exactamente en un solo lugar. No tendrá que preocuparse de que diferentes partes de la aplicación sean incoherentes con el modo en que se aplican las reglas: toda la lógica de validación se definirá en un solo lugar y se usará en todas partes. Esto mantiene el código muy limpio y hace que sea fácil de mantener y evolucionar. También significa que respeta totalmente el principio DRY.

Adición de formato al modelo de película

Abra el archivo Movie.vb. El espacio de nombres System.ComponentModel.DataAnnotations proporciona atributos de formato además del conjunto integrado de atributos de validación. Aplicará el atributo DisplayFormat y un valor de enumeración DataType a la fecha de lanzamiento y a los campos de precio. En el código siguiente se muestran las propiedades ReleaseDate y Price con el atributo DisplayFormat adecuado.

<DataType(DataType.Date)>
    Public Property ReleaseDate() As Date

     <DataType(DataType.Currency)>
    Public Property Price() As Decimal

Como alternativa, podría establecer explícitamente un valor DataFormatString. En el código siguiente se muestra la propiedad de fecha de lanzamiento con una cadena de formato de fecha (es decir, "d"). Lo usaría para especificar que no quiere la hora como parte de la fecha de lanzamiento.

<DisplayFormat(DataFormatString:="{0:d}")>
    Public Property ReleaseDate() As Date

El código siguiente da formato a la propiedad Price como moneda.

<DisplayFormat(DataFormatString:="{0:c}")>
    Public Property Price() As Decimal

A continuación se muestra la clase Movie completa.

Public Class Movie
    Public Property ID() As Integer

    <Required(ErrorMessage:="Title is required")>
    Public Property Title() As String

    <Required(ErrorMessage:="Date is required")>
    <DataType(DataType.Date)>
    Public Property ReleaseDate() As Date

    <Required(ErrorMessage:="Genre must be specified")>
    Public Property Genre() As String

    <Required(ErrorMessage:="Price Required"), Range(1, 100, ErrorMessage:="Price must be between $1 and $100")>
    <DataType(DataType.Currency)>
    Public Property Price() As Decimal

    <StringLength(5)>
    Public Property Rating() As String
End Class

Ejecute la aplicación y vaya al controlador Movies.

8_format_SM

En la siguiente parte de la serie de tutoriales, revisaremos la aplicación y realizaremos algunas mejoras a los métodos Details y Delete generados automáticamente.