Webinaire ouvert «Fluent Validation comme outil de validation des données»



Bonjour encore! Dans le cadre du lancement du cours C # Developer, nous avons organisé une leçon traditionnelle ouverte sur l'outil de validation Fluent . Lors du webinaire, nous avons examiné comment se débarrasser d'un tas d'if par l'exemple de la vérification de l'exactitude du remplissage des données client, étudié l'implémentation interne de la bibliothèque et comment mettre en pratique l'approche Fluent Interface. Le webinaire a été organisé par Alexei Yagur , chef d'équipe chez YouDo.



Pourquoi la validation est-elle nécessaire?


Wikipedia nous dit que la validation (du validus lat. «Sain, fort, fort») est la preuve que les exigences d'un utilisateur, d'un produit, d'un service ou d'un système particulier sont satisfaites. En règle générale, la validation est effectuée si nécessaire, en supposant à la fois une analyse des conditions d'utilisation spécifiées et une évaluation de la conformité des caractéristiques du produit aux exigences existantes. Le résultat de la validation est la conclusion sur la possibilité d'utiliser des produits pour des conditions spécifiques.

Quant à l'outil Fluent Validation , ses connaissances nous permettront de:

  • gagner du temps lors de la résolution de tâches liées à la validation des données;
  • regrouper les chèques maison éparpillés sous une seule forme;
  • Montrez vos connaissances de la validation du café à vos collègues :)

Mais ce n'est que de la théorie, il vaut mieux commencer à pratiquer.

Validation des études de cas: interactif


Ainsi, l'implémentation pratique de la validation en C # est la suivante:



Nous avons une classe Customer, qui a l'ensemble de champs le plus simple: FirstName - nom, LastName - nom de famille, Age - âge. Et il existe une certaine classe CustomerManager qui enregistre, comme nous le voyons, un nouvel utilisateur (acheteur) dans le CustomerRepository et affiche des informations sur la console indiquant que le client a été ajouté avec succès.

Essayons d'ajouter un personnalisé et un gestionnaire qui gérera le personnalisé:

void Main() { var customer = new Customer { FirstName = " ", LastName = "", Age = 57, }; var manager = new CustomerManager(); manager.Add(customer); } 

Le résultat de l'exécution sera la sortie dans la console du texte suivant:

.

Comme vous pouvez le voir, jusqu'ici tout va bien. Mais que se passe-t-il si des données «gâtées» apparaissent soudainement dans notre base de données. Par exemple, si des informations incorrectes sont entrées dans les champs (numéro de téléphone au lieu du nom, âge avec un signe moins, etc.):

 { FirstName = "+79123456789", LastName = "valde@mar.ru", Age = -14, }; 

En conséquence, nous verrons qu'un compteur personnalisé avec un ensemble de données incompréhensible sera également ajouté:

+79123456789 valde@mar.ru .

Naturellement, nous ne voulons pas avoir de telles données dans notre référentiel. Comment nous protégeons-nous? L'option la plus simple est de renvoyer une erreur si, par exemple, nous n'avons pas tous les caractères - lettres. Pour ce faire, nous définissons la condition de FirstName à l'aide de if, et si la condition n'est pas remplie, nous arrêtons la fonction à l'aide de return et affichons le message «Erreur de nom» sur la console. Nous faisons de même avec LastName. Quant à l'âge, nous vérifions ici la plage de nombres, par exemple:

if (customer.Age < 14 || customer.Age > 180)

Supposons maintenant que nous devons ajouter des champs supplémentaires pour l'acheteur , par exemple, un téléphone. Nous validerons le téléphone à la condition que les valeurs saisies commencent par "+79" et n'incluent que des chiffres. Tout cela en soi sera une conception plutôt encombrante, mais si nous voulons ajouter plus d'e-mails?

Quoi qu'il en soit, après avoir effectué les opérations ci-dessus, nous obtenons un tas d'if et une grande feuille de code . Il ne sera pas facile pour un développeur extérieur de comprendre un tel code. Que faire?

Connexion de la validation Fluent


LINQPad a la capacité de connecter la bibliothèque Fluent Validation, ce que nous faisons . De plus, nous créons une autre classe CustomerValidator, qui sera un validateur. En conséquence, nous y prescrivons toutes les règles nécessaires. Nous effectuons des ajustements supplémentaires et supprimons les nombreux if, car ils ne sont plus nécessaires.

En conséquence, notre code final ressemblera à ceci:

 void Main() { var customer = new Customer { FirstName = "Alex2", LastName = "Petrov1", Age = 10, Phone = "+791234567893", Email = "adsf@fadsf3.com" }; var manager = new CustomerManager(); manager.Add(customer); } class Customer { public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } public string Phone { get; set; } public string Email { get; set; } } class CustomerManager { CustomerRepository _repository; CustomerValidator _validator; public CustomerManager() { _repository = new CustomerRepository(); _validator = new CustomerValidator(); } public void Add(Customer customer) { if (!ValidateCustomer(customer)) { return; } _repository.Add(customer); Console.WriteLine($" {customer.FirstName} {customer.LastName}  ."); } private bool ValidateCustomer(Customer customer) { var result = _validator.Validate(customer); if (result.IsValid) { return true; } foreach(var error in result.Errors) { Console.WriteLine(error.ErrorMessage); } return false; } } class CustomerValidator : AbstractValidator<Customer> { public CustomerValidator() { var msg = "   {PropertyName}:  {PropertyValue}"; RuleFor(c => c.FirstName) .Must(c => c.All(Char.IsLetter)).WithMessage(msg); RuleFor(c => c.LastName) .Must(c => c.All(Char.IsLetter)).WithMessage(msg); RuleFor(c => c.Age) .GreaterThan(14).WithMessage(msg) .LessThan(180).WithMessage(msg); RuleFor(c => c.Phone) .Must(IsPhoneValid).WithMessage(msg) .Length(12).WithMessage("    {MinLength}  {MaxLength}.  : {TotalLength}"); RuleFor(c => c.Email) .NotNull().WithMessage(msg) .EmailAddress(); } private bool IsPhoneValid(string phone) { return !(!phone.StartsWith("+79") || !phone.Substring(1).All(c => Char.IsDigit(c))); } } class CustomerRepository { Random _random; public CustomerRepository() { _random = new Random(); } public void Add(Customer customer) { var sleepInSeconds = _random.Next(2, 7); Thread.Sleep(1000 * sleepInSeconds); } } 

Et un peu plus de théorie


Je voudrais ajouter quelques mots sur la validation courante. Cet outil est appelé ainsi en raison de l'interface "fluide". Encore une fois, Wikipedia nous dit que l'interface fluide est un moyen de mettre en œuvre une API orientée objet, visant à augmenter la lisibilité du code source du programme. La définition, comme nous le voyons, contient de nombreux mots longs et beaux, ce qui n'est pas toujours clair. Mais on peut dire le contraire:
"Une interface fluide est un moyen de mettre en œuvre une API orientée objet dans laquelle les méthodes renvoient la même interface sur laquelle elles ont été appelées."
Alexey Yagur
Quant à la bibliothèque elle-même, elle comprend les composants suivants:

  1. La logique de base . Voici un lien vers GitHub où vous pouvez voir la logique principale.
  2. Logique auxiliaire . FluentValidation.ValidatorAttribute est responsable de cette logique.
  3. Partie sensible au contexte . Voir FluentValidation.AspNetCore , FluentValidation.Mvc5 et FluentValidation.WebApi .
  4. Tests . En conséquence, nous sommes intéressés par FluentValidation.Tests.AspNetCore , FluentValidation.Tests.Mvc5 , FluentValidation.Tests.WebApi et FluentValidation.Tests .

C'est tout, étape par étape pour écrire du code, voir la vidéo . En outre, vous pourriez être intéressé par une interaction supplémentaire sur le sujet "Variables dans les textes d'erreur" , que l'enseignant a organisé vers la fin du webinaire.

Rendez-vous au cours de développeur C # !

Source: https://habr.com/ru/post/fr472604/


All Articles