Ajout de la validation
par Rick Anderson
Remarque
Une version mise à jour de ce didacticiel est disponible ici à l’aide de la dernière version de Visual Studio. Le nouveau tutoriel utilise ASP.NET Core MVC, qui fournit de nombreuses améliorations sur ce didacticiel.
Ce didacticiel décrit ASP.NET Core MVC avec des contrôleurs et des vues. Razor Pages est une nouvelle alternative dans ASP.NET Core, un modèle de programmation basé sur des pages qui facilite la création d’une interface utilisateur web plus facile et plus productive. Nous vous recommandons de suivre le didacticiel sur les pages Razor avant la version MVC. Le didacticiel sur les pages Razor :
- est plus facile à suivre ;
- couvre davantage de fonctionnalités ;
- Est l’approche recommandée pour le développement d’applications.
Dans cette section, vous allez ajouter une logique de validation au Movie
modèle et vous vous assurerez que les règles de validation sont appliquées chaque fois qu’un utilisateur tente de créer ou de modifier un film à l’aide de l’application.
Garder les choses sèches
L’un des principaux principes de conception de ASP.NET MVC est DRY (« Ne pas répéter vous-même »). ASP.NET MVC vous encourage à spécifier des fonctionnalités ou un comportement une seule fois, puis à les refléter partout dans une application. Cela réduit la quantité de code dont vous avez besoin pour écrire et rend le code que vous écrivez moins sujette à des erreurs et plus facile à gérer.
La prise en charge de la validation fournie par ASP.NET MVC et Entity Framework Code First est un excellent exemple du principe DRY en action. Vous pouvez spécifier de manière déclarative des règles de validation à un emplacement (dans la classe de modèle) et les règles sont appliquées partout dans l’application.
Examinons comment tirer parti de cette prise en charge de validation dans l’application vidéo.
Ajout de règles de validation au modèle vidéo
Vous commencerez par ajouter une logique de validation à la Movie
classe.
Ouvrez le fichier Movie.cs. Notez que l’espace System.ComponentModel.DataAnnotations
de noms ne contient System.Web
pas . DataAnnotations fournit un ensemble intégré d’attributs de validation que vous pouvez appliquer de manière déclarative à n’importe quelle classe ou propriété. (Il contient également des attributs de mise en forme tels que DataType qui aide à mettre en forme et ne fournit aucune validation.)
À présent, mettez à jour la Movie
classe pour tirer parti des attributs intégrésRequired
, StringLength
RegularExpression et Range
validation. Remplacez la Movie
classe par ce qui suit :
public class Movie
{
public int ID { get; set; }
[StringLength(60, MinimumLength = 3)]
public string Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z]*$")]
[Required]
[StringLength(30)]
public string Genre { get; set; }
[Range(1, 100)]
[DataType(DataType.Currency)]
public decimal Price { get; set; }
[RegularExpression(@"^[A-Z]+[a-zA-Z]*$")]
[StringLength(5)]
public string Rating { get; set; }
}
L’attribut StringLength
définit la longueur maximale de la chaîne et définit cette limitation sur la base de données. Par conséquent, le schéma de base de données change. Cliquez avec le bouton droit sur la table Films dans l’Explorateur de serveurs, puis cliquez sur Ouvrir la définition de table :
Dans l’image ci-dessus, vous pouvez voir que tous les champs de chaîne sont définis sur NVARCHAR (MAX). Nous allons utiliser des migrations pour mettre à jour le schéma. Générez la solution, puis ouvrez la fenêtre Gestionnaire de package console, puis entrez les commandes suivantes :
add-migration DataAnnotations
update-database
Une fois cette commande terminée, Visual Studio ouvre le fichier de classe qui définit la nouvelle DbMigration
classe dérivée avec le nom spécifié (DataAnnotations
) et, dans la Up
méthode, vous pouvez voir le code qui met à jour les contraintes de schéma :
public override void Up()
{
AlterColumn("dbo.Movies", "Title", c => c.String(maxLength: 60));
AlterColumn("dbo.Movies", "Genre", c => c.String(nullable: false, maxLength: 30));
AlterColumn("dbo.Movies", "Rating", c => c.String(maxLength: 5));
}
Le Genre
champ n’est plus nullable (autrement dit, vous devez entrer une valeur). Le Rating
champ a une longueur maximale de 5 et Title
a une longueur maximale de 60. La longueur minimale de 3 sur Title
et la plage sur Price
laquelle elle n’a pas créé de modifications de schéma.
Examinez le schéma movie :
Les champs de chaîne affichent les nouvelles limites de longueur et Genre
ne sont plus vérifiés comme nullables.
Les attributs de validation spécifient le comportement que vous souhaitez appliquer sur les propriétés du modèle sur lesquels ils sont appliqués. Les attributs Required
et MinimumLength
indiquent qu’une propriété doit avoir une valeur, mais rien n’empêche un utilisateur d’entrer un espace blanc pour satisfaire cette validation. L’attribut RegularExpression est utilisé pour limiter les caractères pouvant être entrés. Dans le code ci-dessus, Genre
et Rating
doivent utiliser uniquement des lettres (les espaces blancs, les chiffres et les caractères spéciaux ne sont pas autorisés). L’attribut Range
limite une valeur à une plage spécifiée. L’attribut StringLength
vous permet de définir la longueur maximale d’une propriété de chaîne, et éventuellement sa longueur minimale. Les types valeur (par exemple decimal, int, float, DateTime
) sont intrinsèquement requis et n’ont pas besoin de l’attribut Required
.
Code First garantit que les règles de validation que vous spécifiez sur une classe de modèle sont appliquées avant que l’application enregistre les modifications dans la base de données. Par exemple, le code ci-dessous lève une exception DbEntityValidationException lorsque la SaveChanges
méthode est appelée, car plusieurs valeurs de propriété requises Movie
sont manquantes :
MovieDBContext db = new MovieDBContext();
Movie movie = new Movie();
movie.Title = "Gone with the Wind";
db.Movies.Add(movie);
db.SaveChanges(); // <= Will throw server side validation exception
Le code ci-dessus lève l’exception suivante :
La validation a échoué pour une ou plusieurs entités. Pour plus d’informations, consultez la propriété « EntityValidationErrors ».
Le fait de disposer de règles de validation appliquées automatiquement par le .NET Framework permet de rendre votre application plus robuste. Cela garantit également que vous n’oublierez pas de valider un élément et que vous n’autoriserez pas par inadvertance l’insertion de données incorrectes dans la base de données.
Interface utilisateur d’erreur de validation dans ASP.NET MVC
Exécutez l’application et accédez à l’URL /Movies .
Cliquez sur le lien Créer un nouveau film pour ajouter un nouveau film. Remplissez le formulaire avec des valeurs non valides. Dès que la validation côté client jQuery détecte l’erreur, elle affiche un message d’erreur.
Remarque
pour prendre en charge la validation jQuery pour les paramètres régionaux non anglais qui utilisent une virgule (« , ») pour un point décimal, vous devez inclure la globalisation NuGet comme décrit précédemment dans ce didacticiel.
Notez que le formulaire a automatiquement utilisé une couleur de bordure rouge pour mettre en surbrillance les zones de texte qui contiennent des données non valides et a émis un message d’erreur de validation approprié en regard de chacun d’eux. Les erreurs sont appliquées à la fois côté client (à l’aide de JavaScript et jQuery) et côté serveur (au cas où un utilisateur aurait désactivé JavaScript).
Un avantage réel est que vous n’avez pas besoin de modifier une seule ligne de code dans la classe ou dans la MoviesController
vue Create.cshtml afin d’activer cette interface utilisateur de validation. Le contrôleur et les vues créées précédemment dans ce didacticiel ont détecté les règles de validation que vous avez spécifiées à l’aide des attributs de validation sur les propriétés de la classe de modèle Movie
. Testez la validation à l’aide de la méthode d’action Edit
. La même validation est appliquée.
Les données de formulaire ne sont pas envoyées au serveur tant qu’il y a des erreurs de validation côté client. Vous pouvez le vérifier en plaçant un point d’arrêt dans la méthode HTTP Post, à l’aide de l’outil fiddler ou des outils de développement IE F12.
Comment la validation se produit dans la méthode Create View et Create Action
Vous vous demandez peut-être comment l’interface utilisateur de validation a été générée sans aucune mise à jour du code dans le contrôleur ou dans les vues. La liste suivante montre à quoi ressemblent les Create
méthodes de la MovieController
classe. Ils ne sont pas modifiés par rapport à la façon dont vous les avez créés précédemment dans ce tutoriel.
public ActionResult Create()
{
return View();
}
// POST: /Movies/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ID,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
if (ModelState.IsValid)
{
db.Movies.Add(movie);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(movie);
}
La première méthode d’action (HTTP GET) Create
affiche le formulaire de création initial. La deuxième version ([HttpPost]
) gère la publication de formulaire. La deuxième Create
méthode (la HttpPost
version) vérifie ModelState.IsValid
si le film a des erreurs de validation. L’obtention de cette propriété évalue tous les attributs de validation qui ont été appliqués à l’objet. Si l’objet a des erreurs de validation, la Create
méthode réaffiche le formulaire. S’il n’y a pas d’erreur, la méthode enregistre le nouveau film dans la base de données. Dans notre exemple de film, le formulaire n’est pas publié sur le serveur lorsqu’il y a des erreurs de validation détectées côté client ; la deuxième Create
méthode n’est jamais appelée. Si vous désactivez JavaScript dans votre navigateur, la validation du client est désactivée et la méthode HTTP POST Create
obtient ModelState.IsValid
pour vérifier si le film contient des erreurs de validation.
Vous pouvez définir un point d’arrêt dans la méthode HttpPost Create
et vérifier que la méthode n’est jamais appelée. La validation côté client n’enverra pas les données du formulaire quand des erreurs de validation seront détectées. Si vous désactivez JavaScript dans votre navigateur et que vous envoyez ensuite le formulaire avec des erreurs, le point d’arrêt sera atteint. Vous bénéficiez toujours d’une validation complète sans JavaScript. L’image suivante montre comment désactiver JavaScript dans Internet Explorer.
L’illustration suivante montre comment désactiver JavaScript dans le navigateur FireFox.
L’illustration suivante montre comment désactiver JavaScript dans le navigateur Chrome.
Vous trouverez ci-dessous le modèle de vue Create.cshtml que vous avez généré précédemment dans le didacticiel. Il est utilisé par les méthodes d’action ci-dessus à la fois pour afficher le formulaire initial et pour le réafficher en cas d’erreur.
@model MvcMovie.Models.Movie
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Movie</h4>
<hr />
@Html.ValidationSummary(true)
<div class="form-group">
@Html.LabelFor(model => model.Title, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Title)
@Html.ValidationMessageFor(model => model.Title)
</div>
</div>
@*Fields removed for brevity.*@
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
Notez comment le code utilise un Html.EditorFor
assistance pour générer l’élément <input>
pour chaque Movie
propriété. En regard de cet assistance, il s’agit d’un appel à la méthode d’assistance Html.ValidationMessageFor
. Ces deux méthodes d’assistance fonctionnent avec l’objet de modèle passé par le contrôleur à la vue (dans ce cas, un Movie
objet). Ils recherchent automatiquement les attributs de validation spécifiés sur le modèle et affichent les messages d’erreur appropriés.
Le grand avantage de cette approche est que ni le contrôleur ni le modèle de vue Create
ne savent rien des règles de validation appliquées ou des messages d’erreur affichés. Les règles de validation et les chaînes d’erreur sont spécifiées uniquement dans la classe Movie
. Ces mêmes règles de validation sont automatiquement appliquées à la vue Edit
et à tous les autres modèles de vues que vous pouvez créer et qui modifient votre modèle.
Si vous souhaitez modifier la logique de validation ultérieurement, vous pouvez le faire à un seul endroit en ajoutant des attributs de validation au modèle (dans cet exemple, la movie
classe). Vous n’aurez pas à vous soucier des différentes parties de l’application qui pourraient être incohérentes avec la façon dont les règles sont appliquées. Toute la logique de validation sera définie à un seul emplacement et utilisée partout. Le code est ainsi très propre, facile à mettre à jour et évolutif. Et cela signifie que vous respecterez pleinement le principe DRY .
Utilisation d’attributs DataType
Ouvrez le fichier Movie.cs et examinez la classe Movie
. L’espace de noms System.ComponentModel.DataAnnotations
fournit des attributs de mise en forme en plus de l’ensemble intégré d’attributs de validation. Nous avons déjà appliqué une valeur d’énumération DataType
aux champs de date de sortie et de prix. Le code suivant illustre les propriétés ReleaseDate
et Price
avec l’attribut DataType
approprié.
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[DataType(DataType.Currency)]
public decimal Price { get; set; }
Les attributs DataType fournissent uniquement des conseils pour le moteur de vue pour mettre en forme les données (et fournir des attributs tels que <a>
pour l’URL et <a href="mailto:EmailAddress.com">
pour l’e-mail). Vous pouvez utiliser l’attribut RegularExpression pour valider le format des données. L’attribut DataType est utilisé pour spécifier un type de données plus spécifique que le type intrinsèque de base de données, ils ne sont pas des attributs de validation. Dans le cas présent, nous voulons uniquement effectuer le suivi de la date, pas de la date et de l’heure. L’énumération DataType fournit de nombreux types de données, tels que Date, Heure, PhoneNumber, Currency, EmailAddress et bien plus encore. L’attribut DataType
peut également permettre à l’application de fournir automatiquement des fonctionnalités propres au type. Par exemple, un mailto:
lien peut être créé pour DataType.EmailAddress, et un sélecteur de date peut être fourni pour DataType.Date dans les navigateurs qui prennent en charge HTML5. Les attributs DataType émettent des attributs HTML 5 data - (tiret de données prononcés) que les navigateurs HTML 5 peuvent comprendre. Les attributs DataType ne fournissent aucune validation.
DataType.Date
ne spécifie pas le format de la date qui s’affiche. Par défaut, le champ de données s’affiche selon les formats par défaut basés sur CultureInfo du serveur.
L’attribut DisplayFormat
est utilisé pour spécifier explicitement le format de date :
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime EnrollmentDate { get; set; }
Le ApplyFormatInEditMode
paramètre spécifie que la mise en forme spécifiée doit également être appliquée lorsque la valeur est affichée dans une zone de texte pour modification. (Vous ne souhaiterez peut-être pas que pour certains champs , par exemple, pour les valeurs monétaires, vous ne souhaiterez peut-être pas le symbole monétaire dans la zone de texte à modifier.)
Vous pouvez utiliser l’attribut DisplayFormat lui-même, mais il est généralement judicieux d’utiliser également l’attribut DataType . L’attribut DataType
transmet la sémantique des données par opposition à la façon de l’afficher sur un écran et fournit les avantages suivants que vous n’obtenez DisplayFormat
pas :
- Le navigateur peut activer les fonctionnalités HTML5 (par exemple pour afficher un contrôle de calendrier, le symbole monétaire approprié aux paramètres régionaux, les liens de messagerie, etc.).
- Par défaut, le navigateur affiche les données au format approprié en fonction de vos paramètres régionaux.
- L’attribut DataType peut permettre à MVC de choisir le modèle de champ approprié pour afficher les données (displayFormat s’il est utilisé par lui-même utilise le modèle de chaîne). Pour plus d’informations, consultez les modèles ASP.NET MVC 2 de Brad Wilson. (Bien que écrit pour MVC 2, cet article s’applique toujours à la version actuelle de ASP.NET MVC.)
Si vous utilisez l’attribut DataType
avec un champ de date, vous devez également spécifier l’attribut DisplayFormat
pour vous assurer que le champ s’affiche correctement dans les navigateurs Chrome. Pour plus d’informations, consultez ce thread StackOverflow.
Remarque
La validation jQuery ne fonctionne pas avec l’attribut Range et DateTime. Par exemple, le code suivant affiche toujours une erreur de validation côté client, même quand la date se trouve dans la plage spécifiée :
[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]
Vous devez désactiver la validation de date jQuery pour utiliser l’attribut Range avec DateTime. Il n’est généralement pas recommandé de compiler des dates dures dans vos modèles. Par conséquent, l’utilisation de l’attribut Range et de DateTime est déconseillée.
Le code suivant illustre la combinaison d’attributs sur une seule ligne :
public class Movie
{
public int ID { get; set; }
[Required,StringLength(60, MinimumLength = 3)]
public string Title { get; set; }
[Display(Name = "Release Date"),DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[Required]
public string Genre { get; set; }
[Range(1, 100),DataType(DataType.Currency)]
public decimal Price { get; set; }
[Required,StringLength(5)]
public string Rating { get; set; }
}
Dans la partie suivante de la série, nous allons examiner l’application et apporter des améliorations aux méthodes Details
et Delete
générées automatiquement.