Fluent Validation in C# - L'outil de validation de données puissant et facile à utiliser
La validation des données est l'un des piliers d'un développement logiciel fiable, et dans les applications .NET modernes, vous avez besoin d'un moyen robuste, maintenable et évolutif pour la gérer. C'est là qu'intervient FluentValidation, une bibliothèque .NET populaire permettant de construire des règles de validation fortement typées.
Dans son tutoriel vidéo approfondi "Fluent Validation in C# - The Powerful Yet Easy Data Validation Tool", Tim Corey emmène les spectateurs à travers le processus d'utilisation de FluentValidation, étape par étape. Dans cet article, nous suivrons la démarche de Tim, en résumant les points clés et les exemples de code tout en intégrant des concepts pertinents tels que les validateurs personnalisés, le chaînage de validateurs, l'intégration ASP.NET et la prise en charge des anciens runtimes tels que .NET Core 3.1 et .NET Standard 2.0.
Introduction : Pourquoi FluentValidation ?
Tim commence la vidéo en expliquant comment la validation des données devient souvent répétitive et désordonnée. Par exemple, copier et coller des règles de validation similaires dans différentes parties d'un projet viole le principe DRY (Don't Repeat Yourself). Il présente FluentValidation, une bibliothèque de validation .NET gratuite, puissante et fonctionnant même sur des modèles que vous ne possédez pas, ce qui la rend idéale pour les projets commerciaux.
Tim insiste sur l'importance de mettre en pratique ce que l'on apprend et renvoie les spectateurs à sa série de défis hebdomadaires pour renforcer leurs compétences.
Vue d'ensemble de l'application démo
Tim utilise une application de démonstration WinForms dans laquelle un utilisateur peut entrer :
-
Prénom
-
Nom de famille
-
Solde du compte
- Date de naissance
Bien qu'il s'agisse d'une démo d'interface utilisateur, les principes de validation s'appliquent tout aussi bien à ASP.NET Core, aux tests d'API et même aux applications de console.
Le danger de faire confiance aux données de l'utilisateur
À ce stade, Tim rappelle aux développeurs qu'il ne faut jamais faire confiance à l'utilisateur : "Ne jamais faire confiance à l'utilisateur Les entrées sont souvent imprévisibles, comme le fait de taper "dix" pour l'âge au lieu de 10. Il est essentiel de valider ces données avant de les enregistrer dans la base de données.
Il présente des exemples de règles de validation :
-
Les noms et prénoms ne doivent pas être vides.
-
Le solde du compte doit respecter les règles financières, telles qu'une exigence minimale pour le parrainage financier.
- La date de naissance ne doit pas se situer dans le futur ou remonter à plus de 120 ans.
Qu'en est-il de la logique de validation ?
Tim explore les options de configuration des validateurs :
-
À l'intérieur du formulaire d'interface utilisateur
-
Dans la classe de modèle utilisant des annotations de données
- Dans une classe de validation séparée utilisant FluentValidation
Il note que les annotations de données sont limitées et souvent inadaptées lorsque l'on travaille avec des bibliothèques externes ou lorsque l'on a besoin d'une logique de validation plus personnalisée.
Installation de FluentValidation
À l'aide de Visual Studio, Tim ajoute FluentValidation à son projet via NuGet. Il installe la version 8.1.0 mais note que FluentValidation est multiplateforme et compatible avec :
-
.NET Standard 2.0
-
.NET Core
-
ASP.NET
-
WPF
-
Xamarin
- En savoir plus
La configuration de Tim fonctionne également pour ceux qui ont besoin de la prise en charge d'anciens runtimes, notamment FluentValidation 11, qui prend en charge .NET Core 3.1 et les versions antérieures.
Création d'une classe de validateur
Tim montre comment construire des règles de validation fortement typées en créant une nouvelle classe :
public class PersonValidator : AbstractValidator<Person>
public class PersonValidator : AbstractValidator<Person>
Cette classe contient toute la logique de validation du modèle Person. En utilisant l'interface fluide, les règles de validation sont définies à l'intérieur du constructeur.
Première règle de validation : Prénom
Tim écrit une règle à l'aide d'une expression lambda :
RuleFor(p => p.FirstName).NotEmpty();
RuleFor(p => p.FirstName).NotEmpty();
Il utilise un validateur var pour valider l'objet Personne :
var validator = new PersonValidator();
ValidationResult results = validator.Validate(person);
var validator = new PersonValidator();
ValidationResult results = validator.Validate(person);
Il passe ensuite en revue tous les échecs de validation pour afficher des messages conviviaux dans une liste déroulante.
Longueur des chaînes et messages personnalisés
Tim étend la règle de validation :
RuleFor(p => p.FirstName)
.NotEmpty().WithMessage("First name is empty")
.Length(2, 50).WithMessage("Length of first name is invalid");
RuleFor(p => p.FirstName)
.NotEmpty().WithMessage("First name is empty")
.Length(2, 50).WithMessage("Length of first name is invalid");
En utilisant des validateurs en chaîne, cette règle permet de s'assurer que le nom n'est ni vide, ni trop court ou trop long. Tim introduit Cascade(CascadeMode.Stop) pour arrêter la validation au premier échec.
Validation personnalisée : Caractères valides dans les noms
Tim met en œuvre un validateur personnalisé à l'aide d'une méthode appelée :
private bool BeAValidName(string name)
private bool BeAValidName(string name)
Cette méthode supprime les espaces et les tirets et veille à ce que la chaîne ne contienne que des lettres Unicode, ce qui permet de prendre en charge les caractères internationaux.
La règle personnalisée est appliquée comme suit :
.Must(BeAValidName).WithMessage("{PropertyName} contains invalid characters");
.Must(BeAValidName).WithMessage("{PropertyName} contains invalid characters");
Cette structure de méthode est parfaite pour s'adapter à d'autres champs, tels qu'une fonction logique de validation de code postal personnalisé :
private bool BeAValidPostcode(string postcode)
{
// Add custom logic here to specify a valid postcode format
}
private bool BeAValidPostcode(string postcode)
{
// Add custom logic here to specify a valid postcode format
}
Vous pouvez ensuite l'utiliser dans un validateur tel que :
RuleFor(c => c.Postcode).Must(BeAValidPostcode)
.WithMessage("Please specify a valid postcode");
RuleFor(c => c.Postcode).Must(BeAValidPostcode)
.WithMessage("Please specify a valid postcode");
Ceci est courant dans les projets commerciaux nécessitant la classe publique CustomerValidator ou d'autres validateurs spécifiques à un domaine.
Utilisation de variables intégrées dans les messages d'erreur
Tim montre comment améliorer dynamiquement les messages à l'aide d'espaces réservés tels que :
-
{Nom de la propriété}
-
{Longueur totale}
- {MinLength} et {MaxLength}
Il en résulte des messages d'erreur contextuels tels que :
"Length of First Name is invalid (was 105)"
"Length of First Name is invalid (was 105)"
Cela permet aux utilisateurs de corriger plus facilement les erreurs de saisie.
Nom de famille et localisation
Tim copie la logique de validation de FirstName pour LastName, grâce à un formatage réutilisable avec {PropertyName}. Il mentionne également WithLocalizedMessage() pour ASP.NET ou les applications globales qui nécessitent une prise en charge multilingue.
Important : CascadeMode est spécifique à une règle
Tim précise que CascadeMode.Stop s'applique aux règles individuelles, et non à l'ensemble du modèle. Si FirstName et LastName sont tous deux vides, les deux règles se déclencheront, même si CascadeMode est activé.
Validation de la date de naissance
Ensuite, Tim ajoute une règle pour s'assurer que la date de naissance est réaliste :
private bool BeAValidAge(DateTime dob)
{
var currentYear = DateTime.Now.Year;
var dobYear = dob.Year;
return dobYear <= currentYear && dobYear > (currentYear - 120);
}
private bool BeAValidAge(DateTime dob)
{
var currentYear = DateTime.Now.Year;
var dobYear = dob.Year;
return dobYear <= currentYear && dobYear > (currentYear - 120);
}
Utilisé comme ceci :
RuleFor(p => p.DateOfBirth)
.Must(BeAValidAge)
.WithMessage("Invalid {PropertyName}");
RuleFor(p => p.DateOfBirth)
.Must(BeAValidAge)
.WithMessage("Invalid {PropertyName}");
Il s'agit d'un bon modèle pour valider des données temporelles telles que des dates ou des fenêtres d'expiration.
Réflexions finales et recommandations
Tim conclut en résumant les principaux avantages de FluentValidation :
-
Logique de validation centralisée
-
Facilité de création de validateurs personnalisés
-
Compatible avec .NET 5 et les runtimes plus récents et plus anciens
-
Prise en charge de modèles complexes, de listes et de règles asynchrones
- Idéal pour les amateurs et les projets commerciaux
Il encourage les spectateurs à explorer la documentation de FluentValidation pour une utilisation avancée, y compris les règles imbriquées, la validation des propriétés d'email, et plus encore.
Conclusion
FluentValidation permet aux développeurs .NET de construire des règles de validation fortement typées qui sont réutilisables, expressives et maintenables. Que vous développiez avec .NET Core, .NET 8 ou que vous mainteniez des systèmes hérités sur .NET Core 3.1, cette bibliothèque fait de la validation des données un jeu d'enfant.
Avec des fonctionnalités telles que :
-
L'interface fluide pour l'élaboration de règles
-
Prise en charge de la logique de validation des codes postaux personnalisés
-
Intégration facile avec Visual Studio
-
Compatibilité avec les tests API, WinForms et ASP.NET
- Traitement robuste des échecs de validation
FluentValidation est un outil indispensable dans votre boîte à outils .NET. Pour plus de détails, regardez l'intégralité de la vidéo et abonnez-vous à la Channel de Tim pour d'autres vidéos perspicaces sur C#.
<Astuce:Si vous utilisez FluentValidation pour la première fois, essayez d'implémenter votre propre CustomerValidator avec des règles pour des propriétés telles que public string Name, string Postcode, et bien d'autres. Testez-la à l'aide d'une API fictive ou d'un formulaire d'interface utilisateur pour obtenir une expérience pratique.
