Validation avec l’interface IDataErrorInfo (C#)
par Stephen Walther
Stephen Walther vous montre comment afficher des messages d’erreur de validation personnalisés en implémentant l’interface IDataErrorInfo dans une classe de modèle.
L’objectif de ce tutoriel est d’expliquer une approche pour effectuer la validation dans une application ASP.NET MVC. Vous apprenez à empêcher une personne d’envoyer un formulaire HTML sans fournir de valeurs pour les champs de formulaire obligatoires. Dans ce tutoriel, vous allez apprendre à effectuer une validation à l’aide de l’interface IErrorDataInfo.
Hypothèses
Dans ce tutoriel, je vais utiliser la base de données MoviesDB et la table de base de données Movies. Cette table présente les colonnes suivantes :
Nom de la colonne | Type de données | Null autorisé |
---|---|---|
Id | Int | False |
Titre | Nvarchar(100) | False |
Directeur | Nvarchar(100) | False |
DateReleased | DateTime | False |
Dans ce tutoriel, j’utilise Microsoft Entity Framework pour générer mes classes de modèle de base de données. La classe Movie générée par Entity Framework s’affiche dans la figure 1.
Figure 01 : L’entité Movie (Cliquer pour afficher l’image en taille réelle)
Notes
Pour en savoir plus sur l’utilisation d’Entity Framework pour générer vos classes de modèle de base de données, consultez mon tutoriel intitulé Création de classes de modèle avec Entity Framework.
Classe controller
Nous utilisons le contrôleur d’accueil pour répertorier les films et créer de nouveaux films. Le code de cette classe est contenu dans la liste 1.
Listing 1 - Controllers\HomeController.cs
using System.Linq;
using System.Web.Mvc;
using MvcApplication1.Models;
namespace MvcApplication1.Controllers
{
public class HomeController : Controller
{
private MoviesDBEntities _db = new MoviesDBEntities();
public ActionResult Index()
{
return View(_db.MovieSet.ToList());
}
public ActionResult Create()
{
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = "Id")] Movie movieToCreate)
{
// Validate
if (!ModelState.IsValid)
return View();
// Add to database
try
{
_db.AddToMovieSet(movieToCreate);
_db.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
}
}
La classe de contrôleur Home dans la liste 1 contient deux actions Create(). La première action affiche le formulaire HTML permettant de créer un film. La deuxième action Create() effectue l’insertion réelle du nouveau film dans la base de données. La deuxième action Create() est appelée lorsque le formulaire affiché par la première action Create() est envoyé au serveur.
Notez que la deuxième action Create() contient les lignes de code suivantes :
// Validate
if (!ModelState.IsValid)
return View();
La propriété IsValid retourne false en cas d’erreur de validation. Dans ce cas, la vue Créer qui contient le formulaire HTML pour la création d’un film est réaffichée.
Création d’une classe partielle
La classe Movie est générée par Entity Framework. Vous pouvez voir le code de la classe Movie si vous développez le fichier MoviesDBModel.edmx dans la fenêtre Explorateur de solutions et ouvrez moviesDBModel.Designer. fichier cs dans l’éditeur de code (voir la figure 2).
Figure 02 : Code de l’entité Movie (Cliquer pour afficher l’image en taille réelle)
La classe Movie est une classe partielle. Cela signifie que nous pouvons ajouter une autre classe partielle portant le même nom pour étendre les fonctionnalités de la classe Movie. Nous allons ajouter notre logique de validation à la nouvelle classe partielle.
Ajoutez la classe dans la liste 2 au dossier Models.
Listing 2 - Models\Movie.cs
using System.Collections.Generic;
using System.ComponentModel;
namespace MvcApplication1.Models
{
public partial class Movie
{
}
}
Notez que la classe de la liste 2 inclut le modificateur partiel . Toutes les méthodes ou propriétés que vous ajoutez à cette classe font partie de la classe Movie générée par Entity Framework.
Ajout de méthodes partielles OnChanging et OnChanged
Quand Entity Framework génère une classe d’entité, Entity Framework ajoute automatiquement des méthodes partielles à la classe. Entity Framework génère des méthodes partielles OnChanging et OnChanged qui correspondent à chaque propriété de la classe .
Dans le cas de la classe Movie, Entity Framework crée les méthodes suivantes :
- OnIdChanging
- OnIdChanged
- OnTitleChanging
- OnTitleChanged
- OnDirectorChanging
- OnDirectorChanged
- OnDateReleasedChanging
- OnDateReleasedChanged
La méthode OnChanging est appelée juste avant la modification de la propriété correspondante. La méthode OnChanged est appelée juste après la modification de la propriété.
Vous pouvez tirer parti de ces méthodes partielles pour ajouter une logique de validation à la classe Movie. La classe de mise à jour Movie dans listing 3 vérifie que les propriétés Title et Director sont affectées à des valeurs non vides.
Notes
Une méthode partielle est une méthode définie dans une classe que vous n’avez pas besoin d’implémenter. Si vous n’implémentez pas de méthode partielle, le compilateur supprime la signature de la méthode et tous les appels à la méthode afin qu’il n’y ait aucun coût d’exécution associé à la méthode partielle. Dans l’éditeur Visual Studio Code, vous pouvez ajouter une méthode partielle en tapant le mot clé partiel suivi d’un espace pour afficher la liste des éléments partiels à implémenter.
Listing 3 - Models\Movie.cs
using System.Collections.Generic;
using System.ComponentModel;
namespace MvcApplication1.Models
{
public partial class Movie : IDataErrorInfo
{
private Dictionary<string, string> _errors = new Dictionary<string, string>();
partial void OnTitleChanging(string value)
{
if (value.Trim().Length == 0)
_errors.Add("Title", "Title is required.");
}
partial void OnDirectorChanging(string value)
{
if (value.Trim().Length == 0)
_errors.Add("Director", "Director is required.");
}
}
}
Par exemple, si vous tentez d’affecter une chaîne vide à la propriété Title, un message d’erreur est affecté à un dictionnaire nommé _errors.
À ce stade, rien ne se passe réellement lorsque vous affectez une chaîne vide à la propriété Title et qu’une erreur est ajoutée au champ _errors privé. Nous devons implémenter l’interface IDataErrorInfo pour exposer ces erreurs de validation à l’infrastructure MVC ASP.NET.
Implémentation de l’interface IDataErrorInfo
L’interface IDataErrorInfo fait partie du .NET Framework depuis la première version. Cette interface est très simple :
public interface IDataErrorInfo
{
string this[string columnName] { get; }
string Error { get; }
}
Si une classe implémente l’interface IDataErrorInfo, l’infrastructure MVC ASP.NET utilise cette interface lors de la création d’un instance de la classe. Par exemple, l’action Create() du contrôleur d’accueil accepte une instance de la classe Movie :
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = "Id")] Movie movieToCreate)
{
// Validate
if (!ModelState.IsValid)
return View();
// Add to database
try
{
_db.AddToMovieSet(movieToCreate);
_db.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
L’infrastructure MVC ASP.NET crée la instance du film passée à l’action Create() à l’aide d’un classeur de modèles (DefaultModelBinder). Le classeur de modèles est chargé de créer une instance de l’objet Movie en liant les champs de formulaire HTML à un instance de l’objet Movie.
DefaultModelBinder détecte si une classe implémente ou non l’interface IDataErrorInfo. Si une classe implémente cette interface, le classeur de modèles appelle l’indexeur IDataErrorInfo.this pour chaque propriété de la classe . Si l’indexeur retourne un message d’erreur, le classeur de modèles ajoute automatiquement ce message d’erreur à l’état du modèle.
DefaultModelBinder vérifie également la propriété IDataErrorInfo.Error. Cette propriété est destinée à représenter les erreurs de validation non spécifiques à la propriété associées à la classe . Par exemple, vous pouvez appliquer une règle de validation qui dépend des valeurs de plusieurs propriétés de la classe Movie. Dans ce cas, vous renvoyez une erreur de validation à partir de la propriété Error.
La classe Movie mise à jour dans listing 4 implémente l’interface IDataErrorInfo.
Listing 4 - Models\Movie.cs (implémente IDataErrorInfo)
using System.Collections.Generic;
using System.ComponentModel;
namespace MvcApplication1.Models
{
public partial class Movie : IDataErrorInfo
{
private Dictionary<string, string> _errors = new Dictionary<string, string>();
partial void OnTitleChanging(string value)
{
if (value.Trim().Length == 0)
_errors.Add("Title", "Title is required.");
}
partial void OnDirectorChanging(string value)
{
if (value.Trim().Length == 0)
_errors.Add("Director", "Director is required.");
}
#region IDataErrorInfo Members
public string Error
{
get
{
return string.Empty;
}
}
public string this[string columnName]
{
get
{
if (_errors.ContainsKey(columnName))
return _errors[columnName];
return string.Empty;
}
}
#endregion
}
}
Dans la liste 4, la propriété de l’indexeur vérifie la collection _errors pour voir si elle contient une clé qui correspond au nom de propriété transmis à l’indexeur. Si aucune erreur de validation n’est associée à la propriété, une chaîne vide est retournée.
Vous n’avez pas besoin de modifier le contrôleur Home de quelque manière que ce soit pour utiliser la classe Movie modifiée. La page affichée dans la figure 3 illustre ce qui se passe quand aucune valeur n’est entrée pour les champs Titre ou Formulaire Directeur.
Figure 03 : Formulaire avec des valeurs manquantes (Cliquer pour afficher l’image en taille réelle)
Notez que la valeur DateReleased est validée automatiquement. Étant donné que la propriété DateReleased n’accepte pas les valeurs NULL, DefaultModelBinder génère automatiquement une erreur de validation pour cette propriété lorsqu’elle n’a pas de valeur. Si vous souhaitez modifier le message d’erreur pour la propriété DateReleased, vous devez créer un classeur de modèles personnalisé.
Résumé
Dans ce tutoriel, vous avez appris à utiliser l’interface IDataErrorInfo pour générer des messages d’erreur de validation. Tout d’abord, nous avons créé une classe Movie partielle qui étend les fonctionnalités de la classe Movie partielle générée par Entity Framework. Ensuite, nous avons ajouté une logique de validation aux méthodes partielles OnTitleChanging() et OnDirectorChanging() de la classe Movie. Enfin, nous avons implémenté l’interface IDataErrorInfo afin d’exposer ces messages de validation à l’infrastructure MVC ASP.NET.