Compartir a través de


Agregar la validación al modelo (C#)

por Rick Anderson

Nota:

Aquí hay disponible una versión actualizada de este tutorial en la que se usa ASP.NET MVC 5 y Visual Studio 2013. Es más segura, mucho más sencilla de seguir y muestra más características.

Este tutorial le enseñará los conceptos básicos de la creación de una aplicación web 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, para instalar los requisitos previos haga clic en el vínculo siguiente: Requisitos previos de Visual Studio 2010.

Un proyecto de Visual Web Developer con código fuente de C# está disponible para acompañar este tema. Descargue la versión de C#. Si prefiere Visual Basic, cambie a la versión de Visual Basic 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

Para empezar, agregará lógica de validación a la clase Movie.

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

using 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 int ID { get; set; }

    [Required(ErrorMessage = "Title is required")]
    public string Title { get; set; }

    [Required(ErrorMessage = "Date is required")]
    public DateTime ReleaseDate { get; set; }

    [Required(ErrorMessage = "Genre must be specified")]
    public string Genre { get; set; }

    [Range(1, 100, ErrorMessage = "Price must be between $1 and $100")]
    public decimal Price { get; set; }

    [StringLength(5)]
    public string Rating { get; set; }
}

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).

MovieDBContext db = new MovieDBContext();

Movie movie = new Movie();
movie.Title = "Gone with the Wind";
movie.Price = 0.0M;

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 Movie.cs actualizado:

using System;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int ID { get; set; }

        [Required(ErrorMessage = "Title is required")]
        public string Title { get; set; }

        public DateTime ReleaseDate { get; set; }

        [Required(ErrorMessage = "Genre must be specified")]
        public string Genre { get; set; }

        [Range(1, 100, ErrorMessage = "Price must be between $1 and $100")]
        public decimal Price { get; set; }

        [StringLength(5)]
        public string Rating { get; set; }
    }

    public class MovieDBContext : DbContext
    {
        public DbSet<Movie> Movies { get; set; }
    }
}

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 ni en la vista Create.cshtml para habilitar esta interfaz de usuario de validación. El controlador y las vistas que creado antes en este tutorial han seleccionado automáticamente las reglas de validación que ha especificado 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

public ActionResult Create()
{
    return View();
}

//
// POST: /Movies/Create

[HttpPost]
public ActionResult Create(Movie movie)
{
    if (ModelState.IsValid)
    {
        db.Movies.Add(movie);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    return View(movie);
}

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.

A continuación se muestra la plantilla de vista Create.cshtml a la que ha aplicado scaffolding antes en 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.

@model MvcMovie.Models.Movie
@{
    ViewBag.Title = "Create";
}
<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(model => model.Title)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Title)
            @Html.ValidationMessageFor(model => model.Title)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.ReleaseDate)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ReleaseDate)
            @Html.ValidationMessageFor(model => model.ReleaseDate)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.Genre)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Genre)
            @Html.ValidationMessageFor(model => model.Genre)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.Price)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Price)
            @Html.ValidationMessageFor(model => model.Price)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.Rating)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Rating)
            @Html.ValidationMessageFor(model => model.Rating)
        </div>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}
<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 Movie

Abra el archivo Movie.cs. 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 DateTime ReleaseDate { get; set; }

[DataType(DataType.Currency)] 
public decimal Price { get; set; }

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 DateTime ReleaseDate { get; set; }

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

[DisplayFormat(DataFormatString = "{0:c}")]
public decimal Price { get; set; }

A continuación se muestra la clase Movie completa.

public class Movie
{
    public int ID { get; set; }

    [Required(ErrorMessage = "Title is required")]
    public string Title { get; set; }

    [DisplayFormat(DataFormatString = "{0:d}")]
    public DateTime ReleaseDate { get; set; }

    [Required(ErrorMessage = "Genre must be specified")]
    public string Genre { get; set; }

    [Range(1, 100, ErrorMessage = "Price must be between $1 and $100")]
    [DisplayFormat(DataFormatString = "{0:c}")]
    public decimal Price { get; set; }

    [StringLength(5)]
    public string Rating { get; set; }
}

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.