Parte 9. Adición de validación a una aplicación de ASP.NET Core MVC
Nota:
Esta no es la versión más reciente de este artículo. Para la versión actual, consulte la versión .NET 8 de este artículo.
Advertencia
Esta versión de ASP.NET Core ya no se admite. Para obtener más información, consulte la Directiva de soporte técnico de .NET y .NET Core. Para la versión actual, consulte la versión .NET 8 de este artículo.
Importante
Esta información hace referencia a un producto en versión preliminar, el cual puede sufrir importantes modificaciones antes de que se publique la versión comercial. Microsoft no proporciona ninguna garantía, expresa o implícita, con respecto a la información proporcionada aquí.
Para la versión actual, consulte la versión .NET 8 de este artículo.
Por Rick Anderson
En esta sección:
- Se agrega lógica de validación al modelo
Movie
. - Asegúrese de que las reglas de validación se aplican cada vez que un usuario crea o edita una película.
Respetar el principio DRY
Uno de los principios de diseño de MVC es DRY ("Una vez y solo una"). ASP.NET Core MVC le anima a que especifique la funcionalidad o el comportamiento una sola vez y a que luego los 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 menos propenso a errores, así como más fácil probar y de mantener.
La compatibilidad de validación proporcionada por MVC y Entity Framework Core 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 las reglas se aplican en toda la aplicación.
Eliminar los datos editados anteriormente
En el paso siguiente, se agregan reglas de validación que no permiten valores NULL.
Ejecute la aplicación, vaya a /Movies/Index
, elimine todas las películas enumeradas y detenga la aplicación. La aplicación usará los datos de inicialización la próxima vez que se ejecute.
Adición de reglas de validación al modelo de película
El espacio de nombres DataAnnotations proporciona un conjunto de atributos de validación integrados que se aplican mediante declaración a una clase o propiedad. DataAnnotations también contiene atributos de formato como DataType
que ayudan a aplicar formato y no proporcionan ninguna validación.
Actualice la clase Movie
para aprovechar las ventajas de los atributos de validación integrados Required
, StringLength
, RegularExpression
y Range
y el atributo de formato DataType
.
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MvcMovie.Models;
public class Movie
{
public int Id { get; set; }
[StringLength(60, MinimumLength = 3)]
[Required]
public string? Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
[Required]
[StringLength(30)]
public string? Genre { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
[StringLength(5)]
[Required]
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:
Los atributos
Required
yMinimumLength
indican que una propiedad debe tener un valor, pero nada impide al usuario escribir espacios en blanco para satisfacer esta validación.El atributo
RegularExpression
se usa para limitar los caracteres que se pueden escribir. En el código anterior, "Género":- Solo debe usar letras.
- La primera letra debe estar en mayúsculas. Se permiten espacios en blanco, mientras que no se admiten números ni caracteres especiales.
La "Clasificación" de
RegularExpression
:- Requiere que el primer carácter sea una letra mayúscula.
- Permite caracteres especiales y números en los espacios posteriores. "PG-13" es válido para una "Clasificación", pero se produce un error en un "Género".
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.Los tipos de valor (como
decimal
,int
,float
,DateTime
) son intrínsecamente necesarios y no necesitan el atributo[Required]
.
El que ASP.NET Core aplique automáticamente las reglas de validación ayuda a que su 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.
UI de error de validación
Ejecute la aplicación y navegue al controlador Movies.
Seleccione el vínculo Crear nueva para agregar una nueva película. Rellene el formulario con algunos valores no válidos. En cuanto la validación del lado cliente de jQuery detecta el problema, muestra un mensaje de error.
Nota
Es posible que no pueda escribir comas decimales en campos decimales. Para que la validación de jQuery sea compatible con configuraciones regionales distintas del inglés que usan una coma (",") en lugar de un punto decimal y formatos de fecha distintos del de Estados Unidos, debe seguir unos pasos para globalizar la aplicación. Consulte este comentario 4076 de GitHub para instrucciones sobre cómo agregar la coma decimal.
Observe cómo el formulario presenta automáticamente un mensaje de error de validación adecuado en cada campo que contiene un valor no válido. Los errores se aplican en el lado cliente (con JavaScript y jQuery) 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.cshtml
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 de validación en las propiedades de la clase del modelo Movie
. Pruebe la aplicación mediante el método de acción Edit
y se aplicará la misma validación.
Los datos del formulario no se enviarán al servidor hasta que dejen de producirse errores de validación de cliente. Puede comprobarlo colocando un punto de interrupción en el método HTTP Post
mediante la herramienta Fiddler o las herramientas de desarrollo F12.
Cómo funciona la validación
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 el código siguiente se muestran los dos métodos Create
.
// GET: Movies/Create
public IActionResult Create()
{
return View();
}
// POST: Movies/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
if (ModelState.IsValid)
{
_context.Add(movie);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(movie);
}
El primer método de acción Create
(HTTP GET) muestra el formulario de creación inicial. La segunda versión ([HttpPost]
) controla el envío de formulario. El segundo método Create
(la versión [HttpPost]
) 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. En nuestro ejemplo de película, el formulario no se publica en el servidor si se detectan errores de validación del lado cliente; cuando hay errores de validación en el lado cliente, no se llama nunca al segundo método Create
. Si deshabilita JavaScript en el explorador, se deshabilita también la validación del cliente y puede probar si el método Create
HTTP POST ModelState.IsValid
detecta errores de validación.
Puede establecer un punto de interrupción en el método [HttpPost] Create
y comprobar si nunca se llama al método. La validación del lado cliente no enviará los datos del formulario si se detectan errores de validación. Si deshabilita JavaScript en el explorador y después envía el formulario con errores, se alcanzará el punto de interrupción. Puede seguir obteniendo validación completa sin JavaScript.
En la siguiente imagen se muestra cómo deshabilitar JavaScript en el explorador Firefox.
En la siguiente imagen se muestra cómo deshabilitar JavaScript en el explorador Chrome.
Después de deshabilitar JavaScript, publique los datos no válidos y siga los pasos del depurador.
Una parte de la plantilla de visualización Create.cshtml
se muestra en el marcado siguiente:
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
@*Markup removed for brevity.*@
Los métodos de acción utilizan el marcado anterior para mostrar el formulario inicial y para volver a mostrarlo en caso de error.
El asistente de etiquetas de entrada usa los atributos DataAnnotations y genera los atributos HTML necesarios para la validación de jQuery en el lado cliente. El asistente de etiquetas de validación muestra errores de validación. Para más información, vea Introduction to model validation in ASP.NET Core MVC (Introducción a la validación de modelos en ASP.NET Core MVC).
Lo realmente bueno de este enfoque es que ni el controlador ni la plantilla de vista Create
saben que las reglas de validación actuales se están aplicando 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
. Estas mismas reglas de validación se aplican automáticamente a la vista Edit
y a cualquier otra vista de plantillas creada que edite el modelo.
Cuando necesite cambiar la lógica de validación, puede hacerlo exactamente en un solo lugar mediante la adición de atributos de validación al modelo (en este ejemplo, la clase Movie
). 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.
Uso de atributos DataType
Abra el archivo Movie.cs
y examine la clase Movie
. El espacio de nombres System.ComponentModel.DataAnnotations
proporciona atributos de formato además del conjunto integrado de atributos de validación. Ya hemos aplicado un valor de enumeración DataType
en la fecha de lanzamiento y los campos de precio. En el código siguiente se muestran las propiedades ReleaseDate
y Price
con el atributo DataType
adecuado.
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
Los atributos DataType
solo proporcionan sugerencias para que el motor de vista aplique formato a los datos (y ofrece atributos o elementos como <a>
para las direcciones URL y <a href="mailto:EmailAddress.com">
para el correo electrónico). Use el atributo RegularExpression
para validar el formato de los datos. El atributo DataType
no es un atributo de validación, sino que se usa para especificar un tipo de datos más específico que el tipo intrínseco de la base de datos. En este caso solo queremos realizar un seguimiento de la fecha, no la hora. La enumeración DataType
proporciona muchos tipos de datos, como Date (Fecha), Time (Hora), PhoneNumber (Número de teléfono), Currency (Moneda), EmailAddress (Dirección de correo electrónico), etc. El atributo DataType
también puede permitir que la aplicación proporcione automáticamente características específicas del tipo. Por ejemplo, se puede crear un vínculo mailto:
para DataType.EmailAddress
y se puede proporcionar un selector de datos para DataType.Date
en exploradores compatibles con HTML5. Los atributos DataType
emiten atributos HTML 5 data-
(se pronuncia con el guion) que los exploradores HTML 5 pueden comprender. Los atributos DataType
no proporcionan ninguna validación.
DataType.Date
no especifica el formato de la fecha que se muestra. De manera predeterminada, el campo de datos se muestra según los formatos predeterminados basados en el elemento CultureInfo
del servidor.
El atributo DisplayFormat
se usa para especificar el formato de fecha de forma explícita:
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }
El valor ApplyFormatInEditMode
especifica que el formato se debe aplicar también cuando el valor se muestra en un cuadro de texto para su edición. En algunos campos este comportamiento puede no ser conveniente. Por poner un ejemplo, es probable que con valores de moneda no se quiera que el símbolo de la divisa se incluya en el cuadro de texto editable.
El atributo DisplayFormat
puede usarse por sí solo, pero normalmente se recomienda usar el atributo DataType
. El atributo DataType
transmite la semántica de los datos en contraposición a cómo se representa en una pantalla y ofrece las siguientes ventajas que no proporciona DisplayFormat:
El explorador puede habilitar características de HTML5 (por ejemplo, mostrar un control de calendario, el símbolo de moneda adecuado según la configuración regional, vínculos de correo electrónico, etc.).
De manera predeterminada, el explorador representa los datos con el formato correcto según la configuración regional.
El atributo
DataType
puede habilitar MVC para que elija la plantilla de campo adecuada para representar los datos (DisplayFormat
, si se usa por sí solo, usa la plantilla de cadena).
Nota
La validación de jQuery no funciona con el atributo Range
ni DateTime
. Por ejemplo, el código siguiente siempre muestra un error de validación del lado cliente, incluso cuando la fecha está en el intervalo especificado:
[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]
Debe deshabilitar la validación de fechas de jQuery para usar el atributo Range
con DateTime
. Por lo general no se recomienda compilar fechas fijas en los modelos, así que desaconseja usar el atributo Range
y DateTime
.
El código siguiente muestra la combinación de atributos en una línea:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MvcMovie.Models;
public class Movie
{
public int Id { get; set; }
[StringLength(60, MinimumLength = 3)]
public string Title { get; set; }
[Display(Name = "Release Date"), DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$"), Required, StringLength(30)]
public string Genre { get; set; }
[Range(1, 100), DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
public string Rating { get; set; }
}
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.
Recursos adicionales
En esta sección:
- Se agrega lógica de validación al modelo
Movie
. - Asegúrese de que las reglas de validación se aplican cada vez que un usuario crea o edita una película.
Respetar el principio DRY
Uno de los principios de diseño de MVC es DRY ("Una vez y solo una"). ASP.NET Core MVC le anima a que especifique la funcionalidad o el comportamiento una sola vez y a que luego los 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 menos propenso a errores, así como más fácil probar y de mantener.
La compatibilidad de validación proporcionada por MVC y Entity Framework Core Code First es un buen ejemplo del principio DRY. Puede especificar las reglas de validación mediante declaración en un lugar (en la clase del modelo) y las reglas se aplican en toda la aplicación.
Eliminar los datos editados anteriormente
En el paso siguiente, se agregan reglas de validación que no permiten valores NULL.
Ejecute la aplicación, vaya a /Movies/Index
, elimine todas las películas enumeradas y detenga la aplicación. La aplicación usará los datos de inicialización la próxima vez que se ejecute.
Adición de reglas de validación al modelo de película
El espacio de nombres DataAnnotations proporciona un conjunto de atributos de validación integrados que se aplican mediante declaración a una clase o propiedad. DataAnnotations también contiene atributos de formato como DataType
que ayudan a aplicar formato y no proporcionan ninguna validación.
Actualice la clase Movie
para aprovechar las ventajas de los atributos de validación integrados Required
, StringLength
, RegularExpression
y Range
y el atributo de formato DataType
.
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MvcMovie.Models;
public class Movie
{
public int Id { get; set; }
[StringLength(60, MinimumLength = 3)]
[Required]
public string? Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
[Required]
[StringLength(30)]
public string? Genre { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
[StringLength(5)]
[Required]
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:
Los atributos
Required
yMinimumLength
indican que una propiedad debe tener un valor, pero nada impide al usuario escribir espacios en blanco para satisfacer esta validación.El atributo
RegularExpression
se usa para limitar los caracteres que se pueden escribir. En el código anterior, "Género":- Solo debe usar letras.
- La primera letra debe estar en mayúsculas. Se permiten espacios en blanco, mientras que no se admiten números ni caracteres especiales.
La "Clasificación" de
RegularExpression
:- Requiere que el primer carácter sea una letra mayúscula.
- Permite caracteres especiales y números en los espacios posteriores. "PG-13" es válido para una "Clasificación", pero se produce un error en un "Género".
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.Los tipos de valor (como
decimal
,int
,float
,DateTime
) son intrínsecamente necesarios y no necesitan el atributo[Required]
.
El que ASP.NET Core aplique automáticamente las reglas de validación ayuda a que su 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.
UI de error de validación
Ejecute la aplicación y navegue al controlador Movies.
Seleccione el vínculo Crear nueva para agregar una nueva película. Rellene el formulario con algunos valores no válidos. En cuanto la validación del lado cliente de jQuery detecta el problema, muestra un mensaje de error.
Nota
Es posible que no pueda escribir comas decimales en campos decimales. Para que la validación de jQuery sea compatible con configuraciones regionales distintas del inglés que usan una coma (",") en lugar de un punto decimal y formatos de fecha distintos del de Estados Unidos, debe seguir unos pasos para globalizar la aplicación. Consulte este comentario 4076 de GitHub para instrucciones sobre cómo agregar la coma decimal.
Observe cómo el formulario presenta automáticamente un mensaje de error de validación adecuado en cada campo que contiene un valor no válido. Los errores se aplican en el lado cliente (con JavaScript y jQuery) 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.cshtml
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 de validación en las propiedades de la clase del modelo Movie
. Pruebe la aplicación mediante el método de acción Edit
y se aplicará la misma validación.
Los datos del formulario no se enviarán al servidor hasta que dejen de producirse errores de validación de cliente. Puede comprobarlo colocando un punto de interrupción en el método HTTP Post
mediante la herramienta Fiddler o las herramientas de desarrollo F12.
Cómo funciona la validación
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 el código siguiente se muestran los dos métodos Create
.
// GET: Movies/Create
public IActionResult Create()
{
return View();
}
// POST: Movies/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
if (ModelState.IsValid)
{
_context.Add(movie);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(movie);
}
El primer método de acción Create
(HTTP GET) muestra el formulario de creación inicial. La segunda versión ([HttpPost]
) controla el envío de formulario. El segundo método Create
(la versión [HttpPost]
) 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. En nuestro ejemplo de película, el formulario no se publica en el servidor si se detectan errores de validación del lado cliente; cuando hay errores de validación en el lado cliente, no se llama nunca al segundo método Create
. Si deshabilita JavaScript en el explorador, se deshabilita también la validación del cliente y puede probar si el método Create
HTTP POST ModelState.IsValid
detecta errores de validación.
Puede establecer un punto de interrupción en el método [HttpPost] Create
y comprobar si nunca se llama al método. La validación del lado cliente no enviará los datos del formulario si se detectan errores de validación. Si deshabilita JavaScript en el explorador y después envía el formulario con errores, se alcanzará el punto de interrupción. Puede seguir obteniendo validación completa sin JavaScript.
En la siguiente imagen se muestra cómo deshabilitar JavaScript en el explorador Firefox.
En la siguiente imagen se muestra cómo deshabilitar JavaScript en el explorador Chrome.
Después de deshabilitar JavaScript, publique los datos no válidos y siga los pasos del depurador.
Una parte de la plantilla de visualización Create.cshtml
se muestra en el marcado siguiente:
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
@*Markup removed for brevity.*@
Los métodos de acción utilizan el marcado anterior para mostrar el formulario inicial y para volver a mostrarlo en caso de error.
El asistente de etiquetas de entrada usa los atributos DataAnnotations y genera los atributos HTML necesarios para la validación de jQuery en el lado cliente. El asistente de etiquetas de validación muestra errores de validación. Para más información, vea Introduction to model validation in ASP.NET Core MVC (Introducción a la validación de modelos en ASP.NET Core MVC).
Lo realmente bueno de este enfoque es que ni el controlador ni la plantilla de vista Create
saben que las reglas de validación actuales se están aplicando 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
. Estas mismas reglas de validación se aplican automáticamente a la vista Edit
y a cualquier otra vista de plantillas creada que edite el modelo.
Cuando necesite cambiar la lógica de validación, puede hacerlo exactamente en un solo lugar mediante la adición de atributos de validación al modelo (en este ejemplo, la clase Movie
). 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.
Uso de atributos DataType
Abra el archivo Movie.cs
y examine la clase Movie
. El espacio de nombres System.ComponentModel.DataAnnotations
proporciona atributos de formato además del conjunto integrado de atributos de validación. Ya hemos aplicado un valor de enumeración DataType
en la fecha de lanzamiento y los campos de precio. En el código siguiente se muestran las propiedades ReleaseDate
y Price
con el atributo DataType
adecuado.
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
Los atributos DataType
solo proporcionan sugerencias para que el motor de vista aplique formato a los datos (y ofrece atributos o elementos como <a>
para las direcciones URL y <a href="mailto:EmailAddress.com">
para el correo electrónico). Use el atributo RegularExpression
para validar el formato de los datos. El atributo DataType
no es un atributo de validación, sino que se usa para especificar un tipo de datos más específico que el tipo intrínseco de la base de datos. En este caso solo queremos realizar un seguimiento de la fecha, no la hora. La enumeración DataType
proporciona muchos tipos de datos, como Date (Fecha), Time (Hora), PhoneNumber (Número de teléfono), Currency (Moneda), EmailAddress (Dirección de correo electrónico), etc. El atributo DataType
también puede permitir que la aplicación proporcione automáticamente características específicas del tipo. Por ejemplo, se puede crear un vínculo mailto:
para DataType.EmailAddress
y se puede proporcionar un selector de datos para DataType.Date
en exploradores compatibles con HTML5. Los atributos DataType
emiten atributos HTML 5 data-
(se pronuncia con el guion) que los exploradores HTML 5 pueden comprender. Los atributos DataType
no proporcionan ninguna validación.
DataType.Date
no especifica el formato de la fecha que se muestra. De manera predeterminada, el campo de datos se muestra según los formatos predeterminados basados en el elemento CultureInfo
del servidor.
El atributo DisplayFormat
se usa para especificar el formato de fecha de forma explícita:
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }
El valor ApplyFormatInEditMode
especifica que el formato se debe aplicar también cuando el valor se muestra en un cuadro de texto para su edición. En algunos campos este comportamiento puede no ser conveniente. Por poner un ejemplo, es probable que con valores de moneda no se quiera que el símbolo de la divisa se incluya en el cuadro de texto editable.
El atributo DisplayFormat
puede usarse por sí solo, pero normalmente se recomienda usar el atributo DataType
. El atributo DataType
transmite la semántica de los datos en contraposición a cómo se representa en una pantalla y ofrece las siguientes ventajas que no proporciona DisplayFormat:
El explorador puede habilitar características de HTML5 (por ejemplo, mostrar un control de calendario, el símbolo de moneda adecuado según la configuración regional, vínculos de correo electrónico, etc.).
De manera predeterminada, el explorador representa los datos con el formato correcto según la configuración regional.
El atributo
DataType
puede habilitar MVC para que elija la plantilla de campo adecuada para representar los datos (DisplayFormat
, si se usa por sí solo, usa la plantilla de cadena).
Nota
La validación de jQuery no funciona con el atributo Range
ni DateTime
. Por ejemplo, el código siguiente siempre muestra un error de validación del lado cliente, incluso cuando la fecha está en el intervalo especificado:
[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]
Debe deshabilitar la validación de fechas de jQuery para usar el atributo Range
con DateTime
. Por lo general no se recomienda compilar fechas fijas en los modelos, así que desaconseja usar el atributo Range
y DateTime
.
El código siguiente muestra la combinación de atributos en una línea:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MvcMovie.Models;
public class Movie
{
public int Id { get; set; }
[StringLength(60, MinimumLength = 3)]
public string Title { get; set; }
[Display(Name = "Release Date"), DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$"), Required, StringLength(30)]
public string Genre { get; set; }
[Range(1, 100), DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
public string Rating { get; set; }
}
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.
Recursos adicionales
En esta sección:
- Se agrega lógica de validación al modelo
Movie
. - Asegúrese de que las reglas de validación se aplican cada vez que un usuario crea o edita una película.
Respetar el principio DRY
Uno de los principios de diseño de MVC es DRY ("Una vez y solo una"). ASP.NET Core MVC le anima a que especifique la funcionalidad o el comportamiento una sola vez y a que luego los 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 menos propenso a errores, así como más fácil probar y de mantener.
La compatibilidad de validación proporcionada por MVC y Entity Framework Core Code First es un buen ejemplo del principio DRY. Puede especificar las reglas de validación mediante declaración en un lugar (en la clase del modelo) y las reglas se aplican en toda la aplicación.
Adición de reglas de validación al modelo de película
El espacio de nombres DataAnnotations proporciona un conjunto de atributos de validación integrados que se aplican mediante declaración a una clase o propiedad. DataAnnotations también contiene atributos de formato como DataType
que ayudan a aplicar formato y no proporcionan ninguna validación.
Actualice la clase Movie
para aprovechar las ventajas de los atributos de validación integrados Required
, StringLength
, RegularExpression
y Range
y el atributo de formato DataType
.
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MvcMovie.Models;
public class Movie
{
public int Id { get; set; }
[StringLength(60, MinimumLength = 3)]
[Required]
public string? Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
[Required]
[StringLength(30)]
public string? Genre { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
[StringLength(5)]
[Required]
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:
Los atributos
Required
yMinimumLength
indican que una propiedad debe tener un valor, pero nada impide al usuario escribir espacios en blanco para satisfacer esta validación.El atributo
RegularExpression
se usa para limitar los caracteres que se pueden escribir. En el código anterior, "Género":- Solo debe usar letras.
- La primera letra debe estar en mayúsculas. Se permiten espacios en blanco, mientras que no se admiten números ni caracteres especiales.
La "Clasificación" de
RegularExpression
:- Requiere que el primer carácter sea una letra mayúscula.
- Permite caracteres especiales y números en los espacios posteriores. "PG-13" es válido para una "Clasificación", pero se produce un error en un "Género".
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.Los tipos de valor (como
decimal
,int
,float
,DateTime
) son intrínsecamente necesarios y no necesitan el atributo[Required]
.
El que ASP.NET Core aplique automáticamente las reglas de validación ayuda a que su 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.
UI de error de validación
Ejecute la aplicación y navegue al controlador Movies.
Seleccione el vínculo Crear nueva para agregar una nueva película. Rellene el formulario con algunos valores no válidos. En cuanto la validación del lado cliente de jQuery detecta el problema, muestra un mensaje de error.
Nota
Es posible que no pueda escribir comas decimales en campos decimales. Para que la validación de jQuery sea compatible con configuraciones regionales distintas del inglés que usan una coma (",") en lugar de un punto decimal y formatos de fecha distintos del de Estados Unidos, debe seguir unos pasos para globalizar la aplicación. Consulte este comentario 4076 de GitHub para instrucciones sobre cómo agregar la coma decimal.
Observe cómo el formulario presenta automáticamente un mensaje de error de validación adecuado en cada campo que contiene un valor no válido. Los errores se aplican en el lado cliente (con JavaScript y jQuery) 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.cshtml
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 de validación en las propiedades de la clase del modelo Movie
. Pruebe la aplicación mediante el método de acción Edit
y se aplicará la misma validación.
Los datos del formulario no se enviarán al servidor hasta que dejen de producirse errores de validación de cliente. Puede comprobarlo colocando un punto de interrupción en el método HTTP Post
mediante la herramienta Fiddler o las herramientas de desarrollo F12.
Cómo funciona la validación
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 el código siguiente se muestran los dos métodos Create
.
// GET: Movies/Create
public IActionResult Create()
{
return View();
}
// POST: Movies/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
if (ModelState.IsValid)
{
_context.Add(movie);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(movie);
}
El primer método de acción Create
(HTTP GET) muestra el formulario de creación inicial. La segunda versión ([HttpPost]
) controla el envío de formulario. El segundo método Create
(la versión [HttpPost]
) 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. En nuestro ejemplo de película, el formulario no se publica en el servidor si se detectan errores de validación del lado cliente; cuando hay errores de validación en el lado cliente, no se llama nunca al segundo método Create
. Si deshabilita JavaScript en el explorador, se deshabilita también la validación del cliente y puede probar si el método Create
HTTP POST ModelState.IsValid
detecta errores de validación.
Puede establecer un punto de interrupción en el método [HttpPost] Create
y comprobar si nunca se llama al método. La validación del lado cliente no enviará los datos del formulario si se detectan errores de validación. Si deshabilita JavaScript en el explorador y después envía el formulario con errores, se alcanzará el punto de interrupción. Puede seguir obteniendo validación completa sin JavaScript.
En la siguiente imagen se muestra cómo deshabilitar JavaScript en el explorador Firefox.
En la siguiente imagen se muestra cómo deshabilitar JavaScript en el explorador Chrome.
Después de deshabilitar JavaScript, publique los datos no válidos y siga los pasos del depurador.
Una parte de la plantilla de visualización Create.cshtml
se muestra en el marcado siguiente:
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
@*Markup removed for brevity.*@
Los métodos de acción utilizan el marcado anterior para mostrar el formulario inicial y para volver a mostrarlo en caso de error.
El asistente de etiquetas de entrada usa los atributos DataAnnotations y genera los atributos HTML necesarios para la validación de jQuery en el lado cliente. El asistente de etiquetas de validación muestra errores de validación. Para más información, vea Introduction to model validation in ASP.NET Core MVC (Introducción a la validación de modelos en ASP.NET Core MVC).
Lo realmente bueno de este enfoque es que ni el controlador ni la plantilla de vista Create
saben que las reglas de validación actuales se están aplicando 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
. Estas mismas reglas de validación se aplican automáticamente a la vista Edit
y a cualquier otra vista de plantillas creada que edite el modelo.
Cuando necesite cambiar la lógica de validación, puede hacerlo exactamente en un solo lugar mediante la adición de atributos de validación al modelo (en este ejemplo, la clase Movie
). 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.
Uso de atributos DataType
Abra el archivo Movie.cs
y examine la clase Movie
. El espacio de nombres System.ComponentModel.DataAnnotations
proporciona atributos de formato además del conjunto integrado de atributos de validación. Ya hemos aplicado un valor de enumeración DataType
en la fecha de lanzamiento y los campos de precio. En el código siguiente se muestran las propiedades ReleaseDate
y Price
con el atributo DataType
adecuado.
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
Los atributos DataType
solo proporcionan sugerencias para que el motor de vista aplique formato a los datos (y ofrece atributos o elementos como <a>
para las direcciones URL y <a href="mailto:EmailAddress.com">
para el correo electrónico). Use el atributo RegularExpression
para validar el formato de los datos. El atributo DataType
no es un atributo de validación, sino que se usa para especificar un tipo de datos más específico que el tipo intrínseco de la base de datos. En este caso solo queremos realizar un seguimiento de la fecha, no la hora. La enumeración DataType
proporciona muchos tipos de datos, como Date (Fecha), Time (Hora), PhoneNumber (Número de teléfono), Currency (Moneda), EmailAddress (Dirección de correo electrónico), etc. El atributo DataType
también puede permitir que la aplicación proporcione automáticamente características específicas del tipo. Por ejemplo, se puede crear un vínculo mailto:
para DataType.EmailAddress
y se puede proporcionar un selector de datos para DataType.Date
en exploradores compatibles con HTML5. Los atributos DataType
emiten atributos HTML 5 data-
(se pronuncia con el guion) que los exploradores HTML 5 pueden comprender. Los atributos DataType
no proporcionan ninguna validación.
DataType.Date
no especifica el formato de la fecha que se muestra. De manera predeterminada, el campo de datos se muestra según los formatos predeterminados basados en el elemento CultureInfo
del servidor.
El atributo DisplayFormat
se usa para especificar el formato de fecha de forma explícita:
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }
El valor ApplyFormatInEditMode
especifica que el formato se debe aplicar también cuando el valor se muestra en un cuadro de texto para su edición. En algunos campos este comportamiento puede no ser conveniente. Por poner un ejemplo, es probable que con valores de moneda no se quiera que el símbolo de la divisa se incluya en el cuadro de texto editable.
El atributo DisplayFormat
puede usarse por sí solo, pero normalmente se recomienda usar el atributo DataType
. El atributo DataType
transmite la semántica de los datos en contraposición a cómo se representa en una pantalla y ofrece las siguientes ventajas que no proporciona DisplayFormat:
El explorador puede habilitar características de HTML5 (por ejemplo, mostrar un control de calendario, el símbolo de moneda adecuado según la configuración regional, vínculos de correo electrónico, etc.).
De manera predeterminada, el explorador representa los datos con el formato correcto según la configuración regional.
El atributo
DataType
puede habilitar MVC para que elija la plantilla de campo adecuada para representar los datos (DisplayFormat
, si se usa por sí solo, usa la plantilla de cadena).
Nota
La validación de jQuery no funciona con el atributo Range
ni DateTime
. Por ejemplo, el código siguiente siempre muestra un error de validación del lado cliente, incluso cuando la fecha está en el intervalo especificado:
[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]
Debe deshabilitar la validación de fechas de jQuery para usar el atributo Range
con DateTime
. Por lo general no se recomienda compilar fechas fijas en los modelos, así que desaconseja usar el atributo Range
y DateTime
.
El código siguiente muestra la combinación de atributos en una línea:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MvcMovie.Models;
public class Movie
{
public int Id { get; set; }
[StringLength(60, MinimumLength = 3)]
public string Title { get; set; }
[Display(Name = "Release Date"), DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$"), Required, StringLength(30)]
public string Genre { get; set; }
[Range(1, 100), DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
public string Rating { get; set; }
}
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.
Recursos adicionales
En esta sección:
- Se agrega lógica de validación al modelo
Movie
. - Asegúrese de que las reglas de validación se aplican cada vez que un usuario crea o edita una película.
Respetar el principio DRY
Uno de los principios de diseño de MVC es DRY ("Una vez y solo una"). ASP.NET Core MVC le anima a que especifique la funcionalidad o el comportamiento una sola vez y a que luego los 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 menos propenso a errores, así como más fácil probar y de mantener.
La compatibilidad de validación proporcionada por MVC y Entity Framework Core Code First es un buen ejemplo del principio DRY. Puede especificar las reglas de validación mediante declaración en un lugar (en la clase del modelo) y las reglas se aplican en toda la aplicación.
Adición de reglas de validación al modelo de película
El espacio de nombres DataAnnotations proporciona un conjunto de atributos de validación integrados que se aplican mediante declaración a una clase o propiedad. DataAnnotations también contiene atributos de formato como DataType
que ayudan a aplicar formato y no proporcionan ninguna validación.
Actualice la clase Movie
para aprovechar los atributos de validación integrados Required
, StringLength
, RegularExpression
y Range
.
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MvcMovie.Models
{
public class Movie
{
public int Id { get; set; }
[StringLength(60, MinimumLength = 3)]
[Required]
public string? Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
[Required]
[StringLength(30)]
public string? Genre { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
[StringLength(5)]
[Required]
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:
Los atributos
Required
yMinimumLength
indican que una propiedad debe tener un valor, pero nada impide al usuario escribir espacios en blanco para satisfacer esta validación.El atributo
RegularExpression
se usa para limitar los caracteres que se pueden escribir. En el código anterior, "Género":- Solo debe usar letras.
- La primera letra debe estar en mayúsculas. Se permiten espacios en blanco, mientras que no se admiten números ni caracteres especiales.
La "Clasificación" de
RegularExpression
:- Requiere que el primer carácter sea una letra mayúscula.
- Permite caracteres especiales y números en los espacios posteriores. "PG-13" es válido para una "Clasificación", pero se produce un error en un "Género".
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.Los tipos de valor (como
decimal
,int
,float
,DateTime
) son intrínsecamente necesarios y no necesitan el atributo[Required]
.
El que ASP.NET Core aplique automáticamente las reglas de validación ayuda a que su 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.
UI de error de validación
Ejecute la aplicación y navegue al controlador Movies.
Seleccione el vínculo Crear nueva para agregar una nueva película. Rellene el formulario con algunos valores no válidos. En cuanto la validación del lado cliente de jQuery detecta el problema, muestra un mensaje de error.
Nota
Es posible que no pueda escribir comas decimales en campos decimales. Para que la validación de jQuery sea compatible con configuraciones regionales distintas del inglés que usan una coma (",") en lugar de un punto decimal y formatos de fecha distintos del de Estados Unidos, debe seguir unos pasos para globalizar la aplicación. Consulte este comentario 4076 de GitHub para instrucciones sobre cómo agregar la coma decimal.
Observe cómo el formulario presenta automáticamente un mensaje de error de validación adecuado en cada campo que contiene un valor no válido. Los errores se aplican en el lado cliente (con JavaScript y jQuery) 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.cshtml
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 de validación en las propiedades de la clase del modelo Movie
. Pruebe la aplicación mediante el método de acción Edit
y se aplicará la misma validación.
Los datos del formulario no se enviarán al servidor hasta que dejen de producirse errores de validación de cliente. Puede comprobarlo colocando un punto de interrupción en el método HTTP Post
mediante la herramienta Fiddler o las herramientas de desarrollo F12.
Cómo funciona la validación
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 el código siguiente se muestran los dos métodos Create
.
// GET: Movies/Create
public IActionResult Create()
{
return View();
}
// POST: Movies/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
if (ModelState.IsValid)
{
_context.Add(movie);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(movie);
}
El primer método de acción Create
(HTTP GET) muestra el formulario de creación inicial. La segunda versión ([HttpPost]
) controla el envío de formulario. El segundo método Create
(la versión [HttpPost]
) 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. En nuestro ejemplo de película, el formulario no se publica en el servidor si se detectan errores de validación del lado cliente; cuando hay errores de validación en el lado cliente, no se llama nunca al segundo método Create
. Si deshabilita JavaScript en el explorador, se deshabilita también la validación del cliente y puede probar si el método Create
HTTP POST ModelState.IsValid
detecta errores de validación.
Puede establecer un punto de interrupción en el método [HttpPost] Create
y comprobar si nunca se llama al método. La validación del lado cliente no enviará los datos del formulario si se detectan errores de validación. Si deshabilita JavaScript en el explorador y después envía el formulario con errores, se alcanzará el punto de interrupción. Puede seguir obteniendo validación completa sin JavaScript.
En la siguiente imagen se muestra cómo deshabilitar JavaScript en el explorador Firefox.
En la siguiente imagen se muestra cómo deshabilitar JavaScript en el explorador Chrome.
Después de deshabilitar JavaScript, publique los datos no válidos y siga los pasos del depurador.
Una parte de la plantilla de visualización Create.cshtml
se muestra en el marcado siguiente:
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
@*Markup removed for brevity.*@
Los métodos de acción utilizan el marcado anterior para mostrar el formulario inicial y para volver a mostrarlo en caso de error.
El asistente de etiquetas de entrada usa los atributos DataAnnotations y genera los atributos HTML necesarios para la validación de jQuery en el lado cliente. El asistente de etiquetas de validación muestra errores de validación. Para más información, vea Introduction to model validation in ASP.NET Core MVC (Introducción a la validación de modelos en ASP.NET Core MVC).
Lo realmente bueno de este enfoque es que ni el controlador ni la plantilla de vista Create
saben que las reglas de validación actuales se están aplicando 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
. Estas mismas reglas de validación se aplican automáticamente a la vista Edit
y a cualquier otra vista de plantillas creada que edite el modelo.
Cuando necesite cambiar la lógica de validación, puede hacerlo exactamente en un solo lugar mediante la adición de atributos de validación al modelo (en este ejemplo, la clase Movie
). 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.
Uso de atributos DataType
Abra el archivo Movie.cs
y examine la clase Movie
. El espacio de nombres System.ComponentModel.DataAnnotations
proporciona atributos de formato además del conjunto integrado de atributos de validación. Ya hemos aplicado un valor de enumeración DataType
en la fecha de lanzamiento y los campos de precio. En el código siguiente se muestran las propiedades ReleaseDate
y Price
con el atributo DataType
adecuado.
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
Los atributos DataType
solo proporcionan sugerencias para que el motor de vista aplique formato a los datos (y ofrece atributos o elementos como <a>
para las direcciones URL y <a href="mailto:EmailAddress.com">
para el correo electrónico). Use el atributo RegularExpression
para validar el formato de los datos. El atributo DataType
no es un atributo de validación, sino que se usa para especificar un tipo de datos más específico que el tipo intrínseco de la base de datos. En este caso solo queremos realizar un seguimiento de la fecha, no la hora. La enumeración DataType
proporciona muchos tipos de datos, como Date (Fecha), Time (Hora), PhoneNumber (Número de teléfono), Currency (Moneda), EmailAddress (Dirección de correo electrónico), etc. El atributo DataType
también puede permitir que la aplicación proporcione automáticamente características específicas del tipo. Por ejemplo, se puede crear un vínculo mailto:
para DataType.EmailAddress
y se puede proporcionar un selector de datos para DataType.Date
en exploradores compatibles con HTML5. Los atributos DataType
emiten atributos HTML 5 data-
(se pronuncia con el guion) que los exploradores HTML 5 pueden comprender. Los atributos DataType
no proporcionan ninguna validación.
DataType.Date
no especifica el formato de la fecha que se muestra. De manera predeterminada, el campo de datos se muestra según los formatos predeterminados basados en el elemento CultureInfo
del servidor.
El atributo DisplayFormat
se usa para especificar el formato de fecha de forma explícita:
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }
El valor ApplyFormatInEditMode
especifica que el formato se debe aplicar también cuando el valor se muestra en un cuadro de texto para su edición. En algunos campos este comportamiento puede no ser conveniente. Por poner un ejemplo, es probable que con valores de moneda no se quiera que el símbolo de la divisa se incluya en el cuadro de texto editable.
El atributo DisplayFormat
puede usarse por sí solo, pero normalmente se recomienda usar el atributo DataType
. El atributo DataType
transmite la semántica de los datos en contraposición a cómo se representa en una pantalla y ofrece las siguientes ventajas que no proporciona DisplayFormat:
El explorador puede habilitar características de HTML5 (por ejemplo, mostrar un control de calendario, el símbolo de moneda adecuado según la configuración regional, vínculos de correo electrónico, etc.).
De manera predeterminada, el explorador representa los datos con el formato correcto según la configuración regional.
El atributo
DataType
puede habilitar MVC para que elija la plantilla de campo adecuada para representar los datos (DisplayFormat
, si se usa por sí solo, usa la plantilla de cadena).
Nota
La validación de jQuery no funciona con el atributo Range
ni DateTime
. Por ejemplo, el código siguiente siempre muestra un error de validación del lado cliente, incluso cuando la fecha está en el intervalo especificado:
[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]
Debe deshabilitar la validación de fechas de jQuery para usar el atributo Range
con DateTime
. Por lo general no se recomienda compilar fechas fijas en los modelos, así que desaconseja usar el atributo Range
y DateTime
.
El código siguiente muestra la combinación de atributos en una línea:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MvcMovie.Models
{
public class Movie
{
public int Id { get; set; }
[StringLength(60, MinimumLength = 3)]
public string Title { get; set; }
[Display(Name = "Release Date"), DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$"), Required, StringLength(30)]
public string Genre { get; set; }
[Range(1, 100), DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
public string Rating { get; set; }
}
}
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.
Recursos adicionales
En esta sección:
- Se agrega lógica de validación al modelo
Movie
. - Asegúrese de que las reglas de validación se aplican cada vez que un usuario crea o edita una película.
Respetar el principio DRY
Uno de los principios de diseño de MVC es DRY ("Una vez y solo una"). ASP.NET Core MVC le anima a que especifique la funcionalidad o el comportamiento una sola vez y a que luego los 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 menos propenso a errores, así como más fácil probar y de mantener.
La compatibilidad de validación proporcionada por MVC y Entity Framework Core Code First es un buen ejemplo del principio DRY. Puede especificar las reglas de validación mediante declaración en un lugar (en la clase del modelo) y las reglas se aplican en toda la aplicación.
Adición de reglas de validación al modelo de película
El espacio de nombres DataAnnotations proporciona un conjunto de atributos de validación integrados que se aplican mediante declaración a una clase o propiedad. DataAnnotations también contiene atributos de formato como DataType
que ayudan a aplicar formato y no proporcionan ninguna validación.
Actualice la clase Movie
para aprovechar los atributos de validación integrados Required
, StringLength
, RegularExpression
y Range
.
public class Movie
{
public int Id { get; set; }
[StringLength(60, MinimumLength = 3)]
[Required]
public string Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
[Required]
[StringLength(30)]
public string Genre { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
[StringLength(5)]
[Required]
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:
Los atributos
Required
yMinimumLength
indican que una propiedad debe tener un valor, pero nada impide al usuario escribir espacios en blanco para satisfacer esta validación.El atributo
RegularExpression
se usa para limitar los caracteres que se pueden escribir. En el código anterior, "Género":- Solo debe usar letras.
- La primera letra debe estar en mayúsculas. Se permiten espacios en blanco, pero no se admiten números ni caracteres especiales.
La "Clasificación" de
RegularExpression
:- Requiere que el primer carácter sea una letra mayúscula.
- Permite caracteres especiales y números en los espacios posteriores. "PG-13" es válido para una "Clasificación", pero se produce un error en un "Género".
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.Los tipos de valor (como
decimal
,int
,float
,DateTime
) son intrínsecamente necesarios y no necesitan el atributo[Required]
.
El que ASP.NET Core aplique automáticamente las reglas de validación ayuda a que su 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.
UI de error de validación
Ejecute la aplicación y navegue al controlador Movies.
Pulse el vínculo Crear nueva para agregar una nueva película. Rellene el formulario con algunos valores no válidos. En cuanto la validación del lado cliente de jQuery detecta el problema, muestra un mensaje de error.
Nota
Es posible que no pueda escribir comas decimales en campos decimales. Para que la validación de jQuery sea compatible con configuraciones regionales distintas del inglés que usan una coma (",") en lugar de un punto decimal y formatos de fecha distintos del de Estados Unidos, debe seguir unos pasos para globalizar la aplicación. Consulte este comentario 4076 de GitHub para instrucciones sobre cómo agregar la coma decimal.
Observe cómo el formulario presenta automáticamente un mensaje de error de validación adecuado en cada campo que contiene un valor no válido. Los errores se aplican en el lado cliente (con JavaScript y jQuery) 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.cshtml
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 de validación en las propiedades de la clase del modelo Movie
. Pruebe la aplicación mediante el método de acción Edit
y se aplicará la misma validación.
Los datos del formulario no se enviarán al servidor hasta que dejen de producirse errores de validación de cliente. Puede comprobarlo colocando un punto de interrupción en el método HTTP Post
mediante la herramienta Fiddler o las herramientas de desarrollo F12.
Cómo funciona la validación
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 el código siguiente se muestran los dos métodos Create
.
// GET: Movies/Create
public IActionResult Create()
{
return View();
}
// POST: Movies/Create
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(
[Bind("ID,Title,ReleaseDate,Genre,Price, Rating")] Movie movie)
{
if (ModelState.IsValid)
{
_context.Add(movie);
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(movie);
}
El primer método de acción Create
(HTTP GET) muestra el formulario de creación inicial. La segunda versión ([HttpPost]
) controla el envío de formulario. El segundo método Create
(la versión [HttpPost]
) 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. En nuestro ejemplo de película, el formulario no se publica en el servidor si se detectan errores de validación del lado cliente; cuando hay errores de validación en el lado cliente, no se llama nunca al segundo método Create
. Si deshabilita JavaScript en el explorador, se deshabilita también la validación del cliente y puede probar si el método Create
HTTP POST ModelState.IsValid
detecta errores de validación.
Puede establecer un punto de interrupción en el método [HttpPost] Create
y comprobar si nunca se llama al método. La validación del lado cliente no enviará los datos del formulario si se detectan errores de validación. Si deshabilita JavaScript en el explorador y después envía el formulario con errores, se alcanzará el punto de interrupción. Puede seguir obteniendo validación completa sin JavaScript.
En la siguiente imagen se muestra cómo deshabilitar JavaScript en el explorador Firefox.
En la siguiente imagen se muestra cómo deshabilitar JavaScript en el explorador Chrome.
Después de deshabilitar JavaScript, publique los datos no válidos y siga los pasos del depurador.
La parte de la plantilla de visualización Create.cshtml
se muestra en el marcado siguiente:
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
@*Markup removed for brevity.*@
Los métodos de acción utilizan el marcado anterior para mostrar el formulario inicial y para volver a mostrarlo en caso de error.
El asistente de etiquetas de entrada usa los atributos DataAnnotations y genera los atributos HTML necesarios para la validación de jQuery en el lado cliente. El asistente de etiquetas de validación muestra errores de validación. Para más información, vea Introduction to model validation in ASP.NET Core MVC (Introducción a la validación de modelos en ASP.NET Core MVC).
Lo realmente bueno de este enfoque es que ni el controlador ni la plantilla de vista Create
saben que las reglas de validación actuales se están aplicando 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
. Estas mismas reglas de validación se aplican automáticamente a la vista Edit
y a cualquier otra vista de plantillas creada que edite el modelo.
Cuando necesite cambiar la lógica de validación, puede hacerlo exactamente en un solo lugar mediante la adición de atributos de validación al modelo (en este ejemplo, la clase Movie
). 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.
Uso de atributos DataType
Abra el archivo Movie.cs
y examine la clase Movie
. El espacio de nombres System.ComponentModel.DataAnnotations
proporciona atributos de formato además del conjunto integrado de atributos de validación. Ya hemos aplicado un valor de enumeración DataType
en la fecha de lanzamiento y los campos de precio. En el código siguiente se muestran las propiedades ReleaseDate
y Price
con el atributo DataType
adecuado.
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[Range(1, 100)]
[DataType(DataType.Currency)]
public decimal Price { get; set; }
Los atributos DataType
solo proporcionan sugerencias para que el motor de vista aplique formato a los datos (y ofrece atributos o elementos como <a>
para las direcciones URL y <a href="mailto:EmailAddress.com">
para el correo electrónico). Use el atributo RegularExpression
para validar el formato de los datos. El atributo DataType
no es un atributo de validación, sino que se usa para especificar un tipo de datos más específico que el tipo intrínseco de la base de datos. En este caso solo queremos realizar un seguimiento de la fecha, no la hora. La enumeración DataType
proporciona muchos tipos de datos, como Date (Fecha), Time (Hora), PhoneNumber (Número de teléfono), Currency (Moneda), EmailAddress (Dirección de correo electrónico), etc. El atributo DataType
también puede permitir que la aplicación proporcione automáticamente características específicas del tipo. Por ejemplo, se puede crear un vínculo mailto:
para DataType.EmailAddress
y se puede proporcionar un selector de datos para DataType.Date
en exploradores compatibles con HTML5. Los atributos DataType
emiten atributos HTML 5 data-
(se pronuncia con el guion) que los exploradores HTML 5 pueden comprender. Los atributos DataType
no proporcionan ninguna validación.
DataType.Date
no especifica el formato de la fecha que se muestra. De manera predeterminada, el campo de datos se muestra según los formatos predeterminados basados en el elemento CultureInfo
del servidor.
El atributo DisplayFormat
se usa para especificar el formato de fecha de forma explícita:
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }
El valor ApplyFormatInEditMode
especifica que el formato se debe aplicar también cuando el valor se muestra en un cuadro de texto para su edición. En algunos campos este comportamiento puede no ser conveniente. Por poner un ejemplo, es probable que con valores de moneda no se quiera que el símbolo de la divisa se incluya en el cuadro de texto editable.
El atributo DisplayFormat
puede usarse por sí solo, pero normalmente se recomienda usar el atributo DataType
. El atributo DataType
transmite la semántica de los datos en contraposición a cómo se representa en una pantalla y ofrece las siguientes ventajas que no proporciona DisplayFormat:
El explorador puede habilitar características de HTML5 (por ejemplo, mostrar un control de calendario, el símbolo de moneda adecuado según la configuración regional, vínculos de correo electrónico, etc.).
De manera predeterminada, el explorador representa los datos con el formato correcto según la configuración regional.
El atributo
DataType
puede habilitar MVC para que elija la plantilla de campo adecuada para representar los datos (DisplayFormat
, si se usa por sí solo, usa la plantilla de cadena).
Nota
La validación de jQuery no funciona con el atributo Range
ni DateTime
. Por ejemplo, el código siguiente siempre muestra un error de validación del lado cliente, incluso cuando la fecha está en el intervalo especificado:
[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]
Debe deshabilitar la validación de fechas de jQuery para usar el atributo Range
con DateTime
. Por lo general no se recomienda compilar fechas fijas en los modelos, así que desaconseja usar el atributo Range
y DateTime
.
El código siguiente muestra la combinación de atributos en una línea:
public class Movie
{
public int Id { get; set; }
[StringLength(60, MinimumLength = 3)]
public string Title { get; set; }
[Display(Name = "Release Date"), DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$"), Required, StringLength(30)]
public string Genre { get; set; }
[Range(1, 100), DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
public string Rating { get; set; }
}
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.