Agregar la validación al modelo (C#)
por Rick Anderson
Nota:
Hay disponible aquí una versión actualizada de este tutorial que 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:
- Requisitos previos de Visual Studio Web Developer Express SP1
- Actualización de herramientas de ASP.NET MVC 3
- SQL Server Compact 4.0(runtime + soporte de herramientas)
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 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.
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
.
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.