Partager via


Validation

Conseil

Ce contenu est un extrait du livre électronique Modèles d’application d’entreprise avec .NET MAUI, disponible dans la .documentation .NET ou en tant que PDF téléchargeable gratuitement qui peut être lu hors connexion.

Miniature de la couverture du livre électronique Modèles d’application d’entreprise avec .NET MAUI.

Toute application qui accepte une entrée des utilisateurs doit s’assurer que l’entrée est valide. Une application peut, par exemple, rechercher une entrée qui contient uniquement des caractères dans une plage particulière, est d’une certaine longueur ou correspond à un format particulier. Sans validation, un utilisateur peut fournir des données qui provoquent l’échec de l’application. Une validation appropriée applique des règles d’entreprise et peut empêcher un attaquant d’injecter des données malveillantes.

Dans le contexte du modèle modèle-vue-vue modèle (MVVM), un modèle de vue ou un modèle est souvent nécessaire pour effectuer la validation des données et signaler les erreurs de validation à la vue afin que l’utilisateur puisse les corriger. L’application multiplateforme eShop effectue une validation côté client synchrone des propriétés du modèle de vue et avertit l’utilisateur de toute erreur de validation en mettant en surbrillance le contrôle qui contient les données non valides et en affichant des messages d’erreur qui informent l’utilisateur de la raison pour laquelle les données ne sont pas valides. L’image ci-dessous montre les classes impliquées dans l’exécution de la validation dans l’application multiplateforme eShop.

Classes de validation dans l’application multiplateforme eShop.

Les propriétés de modèle d’affichage qui nécessitent une validation sont de type ValidatableObject<T>, et chaque instance ValidatableObject<T> a des règles de validation ajoutées à sa propriété Validations. La validation est appelée à partir du modèle de vue en appelant la méthode Validate de l’instance ValidatableObject<T>, qui récupère les règles de validation et les exécute sur la propriété ValidatableObject<T>.Value. Toutes les erreurs de validation sont placées dans la propriété Errors de l’instance ValidatableObject<T>, et la propriété IsValid de l’instance ValidatableObject<T> est mise à jour pour indiquer si la validation a réussi ou échoué. Le code suivant montre l’implémentation de l’élément ValidatableObject<T> :

using CommunityToolkit.Mvvm.ComponentModel;
namespace eShop.Validations;
public class ValidatableObject<T> : ObservableObject, IValidity
{
    private IEnumerable<string> _errors;
    private bool _isValid;
    private T _value;
    public List<IValidationRule<T>> Validations { get; } = new();
    public IEnumerable<string> Errors
    {
        get => _errors;
        private set => SetProperty(ref _errors, value);
    }
    public bool IsValid
    {
        get => _isValid;
        private set => SetProperty(ref _isValid, value);
    }
    public T Value
    {
        get => _value;
        set => SetProperty(ref _value, value);
    }
    public ValidatableObject()
    {
        _isValid = true;
        _errors = Enumerable.Empty<string>();
    }
    public bool Validate()
    {
        Errors = Validations
            ?.Where(v => !v.Check(Value))
            ?.Select(v => v.ValidationMessage)
            ?.ToArray()
            ?? Enumerable.Empty<string>();
        IsValid = !Errors.Any();
        return IsValid;
    }
}

La notification de modification de propriété est fournie par la classe ObservableObject. Par conséquent, un contrôle Entry peut être lié à la propriété IsValid de l’instance ValidatableObject<T> dans la classe de modèle de vue pour être informé de la validité ou non des données entrées.

Spécification de règles de validation

Les règles de validation sont spécifiées en créant une classe qui dérive de l’interface IValidationRule<T>, comme illustré dans l’exemple de code suivant :

public interface IValidationRule<T>
{
    string ValidationMessage { get; set; }
    bool Check(T value);
}

Cette interface spécifie qu’une classe de règle de validation doit fournir une méthode Check booléenne utilisée pour effectuer la validation requise, ainsi qu’une propriété ValidationMessage dont la valeur est le message d’erreur de validation qui s’affiche si la validation échoue.

L’exemple de code suivant montre la règle de validation IsNotNullOrEmptyRule<T> utilisée pour effectuer la validation du nom d’utilisateur et du mot de passe entrés par l’utilisateur sur le LoginView lors de l’utilisation de services fictifs dans l’application multiplateforme eShop :

public class IsNotNullOrEmptyRule<T> : IValidationRule<T>
{
    public string ValidationMessage { get; set; }

    public bool Check(T value) =>
        value is string str && !string.IsNullOrWhiteSpace(str);
}

La méthode Check retourne une valeur booléenne indiquant si l’argument value est null, vide ou se compose uniquement de caractères d’espace blanc.

Bien qu’elle ne soit pas utilisée par l’application multiplateforme eShop, l’exemple de code suivant montre une règle de validation pour la validation des adresses e-mail :

public class EmailRule<T> : IValidationRule<T>
{
    private readonly Regex _regex = new(@"^([w.-]+)@([w-]+)((.(w){2,3})+)$");

    public string ValidationMessage { get; set; }

    public bool Check(T value) =>
        value is string str && _regex.IsMatch(str);
}

La méthode Check retourne une valeur booléenne indiquant si l’argument value est une adresse e-mail valide. Pour ce faire, recherchez la première occurrence du modèle d’expression régulière spécifié dans le constructeur Regex dans l’argument value. Vous pouvez déterminer si le modèle d’expression régulière a été trouvé dans la chaîne d’entrée en vérifiant value par rapport à Regex.IsMatch.

Notes

La validation de propriété peut parfois impliquer des propriétés dépendantes. Un exemple de propriétés dépendantes est lorsque l’ensemble de valeurs valides pour la propriété A dépend de la valeur particulière qui a été définie dans la propriété B. Pour vérifier que la valeur de la propriété A est l’une des valeurs autorisées, vous devez récupérer la valeur de la propriété B. En outre, lorsque la valeur de la propriété B change, la propriété A doit être revalidée.

Ajout de règles de validation à une propriété

Dans l’application multiplateforme eShop, affichez les propriétés de modèle qui nécessitent la validation sont déclarées comme de type ValidatableObject<T>, où T est le type des données à valider. L’exemple de code suivant montre un exemple de deux propriétés de ce type :

public ValidatableObject<string> UserName { get; private set; }
public ValidatableObject<string> Password { get; private set; }

Pour que la validation se produise, les règles de validation doivent être ajoutées à la collection Validations de chaque instance ValidatableObject<T>, comme illustré dans l’exemple de code suivant :

private void AddValidations()
{
    UserName.Validations.Add(new IsNotNullOrEmptyRule<string> 
    { 
        ValidationMessage = "A username is required." 
    });

    Password.Validations.Add(new IsNotNullOrEmptyRule<string> 
    { 
        ValidationMessage = "A password is required." 
    });
}

Cette méthode ajoute la règle de validation IsNotNullOrEmptyRule<T> à la collection Validations de chaque instance ValidatableObject<T>, en spécifiant des valeurs pour la propriété ValidationMessage de la règle de validation, qui spécifie le message d’erreur de validation qui s’affichera en cas d’échec de la validation.

Déclenchement de la validation

L’approche de validation utilisée dans l’application multiplateforme eShop peut déclencher manuellement la validation d’une propriété et déclencher automatiquement la validation lorsqu’une propriété change.

Déclenchement manuel de la validation

La validation peut être déclenchée manuellement pour une propriété de modèle de vue. Par exemple, cela se produit dans l’application multiplateforme eShop lorsque l’utilisateur appuie sur le bouton Login sur le LoginView, lors de l’utilisation de services fictifs. Le délégué de commande appelle la méthode MockSignInAsync dans le modèle de vue LoginViewModel, qui appelle la validation en exécutant la méthode Validate, ce qui est illustré dans l’exemple de code suivant :

private bool Validate()
{
    bool isValidUser = ValidateUserName();
    bool isValidPassword = ValidatePassword();
    return isValidUser && isValidPassword;
}

private bool ValidateUserName()
{
    return _userName.Validate();
}

private bool ValidatePassword()
{
    return _password.Validate();
}

La méthode Validate effectue la validation du nom d’utilisateur et du mot de passe entrés par l’utilisateur sur la vue LoginView, en appelant la méthode Validate sur chaque instance ValidatableObject<T>. L’exemple de code suivant montre la méthode Validate dans la classe ValidatableObject<T> :

public bool Validate()
{
    Errors = _validations
        ?.Where(v => !v.Check(Value))
        ?.Select(v => v.ValidationMessage)
        ?.ToArray()
        ?? Enumerable.Empty<string>();

    IsValid = !Errors.Any();

    return IsValid;
}

Cette méthode récupère toutes les règles de validation qui ont été ajoutées à la collection Validations de l’objet. La méthode Check pour chaque règle de validation récupérée est exécutée et la valeur de propriété ValidationMessage pour toute règle de validation qui ne parvient pas à valider les données est ajoutée à la collection Errors de l’instance ValidatableObject<T>. Enfin, la propriété IsValid est définie et sa valeur est retournée à la méthode appelante, indiquant si la validation a réussi ou échoué.

Déclenchement de la validation lorsque les propriétés changent

La validation est également déclenchée automatiquement chaque fois qu’une propriété liée change. Par exemple, lorsqu’une liaison bidirectionnelle dans la vue LoginView définit la propriété UserName ou Password, la validation est déclenchée. L’exemple de code suivant montre comment cela se produit :

<Entry Text="{Binding UserName.Value, Mode=TwoWay}">
    <Entry.Behaviors>
        <behaviors:EventToCommandBehavior
            EventName="TextChanged"
            Command="{Binding ValidateUserNameCommand}" />
    </Entry.Behaviors>
</Entry>

Le contrôle Entry est lié à la propriété UserName.Value de l’instance ValidatableObject<T> et une instance EventToCommandBehavior est ajoutée à la collection Behaviors du contrôle. Ce comportement exécute la commande ValidateUserNameCommand en réponse à l’événement TextChanged déclenché sur l’Entry, qui est déclenché lorsque le texte dans l’Entry change. À son tour, le délégué ValidateUserNameCommand exécute la méthode ValidateUserName, qui exécute la méthode Validate sur l’instance ValidatableObject<T>. Par conséquent, chaque fois que l’utilisateur entre un caractère dans le contrôle Entry pour le nom d’utilisateur, la validation des données entrées est effectuée.

Affichage des erreurs de validation

L’application multiplateforme eShop avertit l’utilisateur de toute erreur de validation en mettant en surbrillance le contrôle qui contient les données non valides avec un arrière-plan rouge et en affichant un message d’erreur qui informe l’utilisateur de la raison pour laquelle les données ne sont pas valides sous le contrôle contenant les données non valides. Lorsque les données non valides sont corrigées, l’arrière-plan revient à l’état par défaut et le message d’erreur est supprimé. L’image ci-dessous montre LoginView dans l’application multiplateforme eShop lorsque des erreurs de validation sont présentes.

Affichage des erreurs de validation lors de la connexion.

Mise en surbrillance d’un contrôle qui contient des données non valides

.NET MAUI offre un certain nombre de façons de présenter des informations de validation aux utilisateurs finaux, mais l’une des méthodes les plus simples consiste à utiliser Triggers. Triggers fournit un moyen de modifier l’état de nos contrôles, généralement pour l’apparence, en fonction d’un événement ou d’une modification de données qui se produit pour un contrôle. Pour la validation, nous allons utiliser un DataTrigger qui écoutera les modifications générées à partir d’une propriété liée et répondra aux modifications. Les contrôles Entry sur la vue LoginView sont configurés à l’aide du code suivant :

<Entry Text="{Binding UserName.Value, Mode=TwoWay}">
    <Entry.Style>
        <OnPlatform x:TypeArguments="Style">
            <On Platform="iOS, Android" Value="{StaticResource EntryStyle}" />
            <On Platform="WinUI" Value="{StaticResource WinUIEntryStyle}" />
        </OnPlatform>
    </Entry.Style>
    <Entry.Behaviors>
        <mct:EventToCommandBehavior
            EventName="TextChanged"
            Command="{Binding ValidateCommand}" />
    </Entry.Behaviors>
    <Entry.Triggers>
        <DataTrigger 
            TargetType="Entry"
            Binding="{Binding UserName.IsValid}"
            Value="False">
            <Setter Property="BackgroundColor" Value="{StaticResource ErrorColor}" />
        </DataTrigger>
    </Entry.Triggers>
</Entry>

DataTrigger spécifie les propriétés suivantes :

Propriété Description
TargetType Type de contrôle auquel appartient le déclencheur.
Binding Balisage de données Binding qui fournira des notifications de modification et une valeur pour la condition de déclencheur.
Value Valeur de données à spécifier quand la condition du déclencheur a été remplie.

Pour cette Entry, nous allons écouter les modifications apportées à la propriété LoginViewModel.UserName.IsValid. Chaque fois que cette propriété déclenche une modification, la valeur est comparée à la propriété Value définie dans DataTrigger. Si les valeurs sont égales, la condition de déclencheur est remplie et tous les objets Setter fournis à DataTrigger seront exécutés. Ce contrôle a un objet unique Setter qui met à jour la propriété BackgroundColor vers une couleur personnalisée définie à l’aide du balisage StaticResource. Lorsqu’une condition Trigger n’est plus remplie, le contrôle rétablit les propriétés définies par l’objet Setter à leur état précédent. Pour plus d’informations sur Triggers, consultez .NET MAUI Docs : Déclencheurs.

Affichage de messages d’erreur

L’interface utilisateur affiche des messages d’erreur de validation dans les contrôles Label sous chaque contrôle dont la validation des données a échoué. L’exemple de code suivant montre l’étiquette Label qui affiche un message d’erreur de validation, si l’utilisateur n’a pas entré de nom d’utilisateur valide :

<Label
    Text="{Binding UserName.Errors, Converter={StaticResource FirstValidationErrorConverter}"
    Style="{StaticResource ValidationErrorLabelStyle}" />

Chaque étiquette est liée à la propriété Errors de l’objet de modèle de vue en cours de validation. La propriété Errors est fournie par la classe ValidatableObject<T> et est de type IEnumerable<string>. Étant donné que la propriété Errors peut contenir plusieurs erreurs de validation, l’instance FirstValidationErrorConverter est utilisée pour récupérer la première erreur de la collection pour affichage.

Résumé

L’application multiplateforme eShop effectue une validation synchrone côté client des propriétés du modèle d’affichage et avertit l’utilisateur des erreurs de validation en mettant en évidence le contrôle qui contient les données non valides et en affichant des messages d’erreur qui informent l’utilisateur de la raison pour laquelle les données ne sont pas valides.

Les propriétés de modèle d’affichage qui nécessitent une validation sont de type ValidatableObject<T>, et chaque instance ValidatableObject<T> a des règles de validation ajoutées à sa propriété Validations. La validation est appelée à partir du modèle de vue en appelant la méthode Validate de l’instance ValidatableObject<T>, qui récupère les règles de validation et les exécute sur la propriété Value ValidatableObject<T>. Toutes les erreurs de validation sont placées dans la propriété Errors de l’instance ValidatableObject<T>, et la propriété IsValid de l’instance ValidatableObject<T> est mise à jour pour indiquer si la validation a réussi ou échoué.