Partager via


Validation dans Les applications d’entreprise

Remarque

Ce livre électronique a été publié au printemps 2017 et n’a pas été mis à jour depuis. Il y a beaucoup dans le livre qui reste précieux, mais certains de la matière est obsolète.

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. La validation applique des règles métier et empêche 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 mobile eShopOnContainers 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. La figure 6-1 montre les classes impliquées dans l’exécution de la validation dans l’application mobile eShopOnContainers.

Classes de validation dans l’application mobile eShopOnContainers

Figure 6-1 : Classes de validation dans l’application mobile eShopOnContainers

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 Validate méthode de l’instance ValidatableObject<T> , qui récupère les règles de validation et les exécute sur la ValidatableObject<T> Value propriété. Toutes les erreurs de validation sont placées dans la Errors propriété de l’instance ValidatableObject<T> et la IsValid propriété de l’instance ValidatableObject<T> est mise à jour pour indiquer si la validation a réussi ou échoué.

La notification de modification de propriété est fournie par la classe ExtendedBindableObject. 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 boolean Check méthode utilisée pour effectuer la validation requise et une ValidationMessage propriété dont la valeur est le message d’erreur de validation qui s’affiche si la validation échoue.

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

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

    public bool Check(T value)  
    {  
        if (value == null)  
        {  
            return false;  
        }  

        var str = value as string;  
        return !string.IsNullOrWhiteSpace(str);  
    }  
}

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

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

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

    public bool Check(T value)  
    {  
        if (value == null)  
        {  
            return false;  
        }  

        var str = value as string;  
        Regex regex = new Regex(@"^([\w\.\-]+)@([\w\-]+)((\.(\w){2,3})+)$");  
        Match match = regex.Match(str);  

        return match.Success;  
    }  
}

La Check méthode retourne un boolean indicateur indiquant si l’argument valeur 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. Si le modèle d’expression régulière a été trouvé dans la chaîne d’entrée peut être déterminé en vérifiant la valeur de la propriété de Success l’objetMatch.

Remarque

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 mobile eShopOnContainers, 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  
    {  
        return _userName;  
    }  
    set  
    {  
        _userName = value;  
        RaisePropertyChanged(() => UserName);  
    }  
}  

public ValidatableObject<string> Password  
{  
    get  
    {  
        return _password;  
    }  
    set  
    {  
        _password = value;  
        RaisePropertyChanged(() => Password);  
    }  
}

Pour que la validation se produise, les règles de validation doivent être ajoutées à la Validations collection de chaque ValidatableObject<T> instance, 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 mobile eShopOnContainers 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 mobile eShopOnContainers lorsque l’utilisateur appuie sur le bouton Connexion sur le , lors de l’utilisation LoginViewde 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 Validate méthode effectue la validation du nom d’utilisateur et du mot de passe entrés par l’utilisateur sur le LoginView, en appelant la méthode Validate sur chaque ValidatableObject<T> instance. L’exemple de code suivant montre la méthode Validate de la ValidatableObject<T> classe :

public bool Validate()  
{  
    Errors.Clear();  

    IEnumerable<string> errors = _validations  
        .Where(v => !v.Check(Value))  
        .Select(v => v.ValidationMessage);  

    Errors = errors.ToList();  
    IsValid = !Errors.Any();  

    return this.IsValid;  
}

Cette méthode efface la Errors collection, puis récupère toutes les règles de validation qui ont été ajoutées à la collection de l’objet Validations . 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 peut également être déclenchée 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 ValidateUserNameCommand réponse à l’événement [TextChanged] qui se déclenche sur le Entry, qui est déclenché lorsque le texte dans les Entry modifications est déclenché. À 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.

Pour plus d’informations sur les comportements, consultez Implémentation de comportements.

Affichage des erreurs de validation

L’application mobile eShopOnContainers informe l’utilisateur de toutes les erreurs de validation en mettant en surbrillance le contrôle qui contient les données non valides avec une ligne rouge et en affichant un message d’erreur qui informe l’utilisateur pourquoi 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, la ligne passe en noir et le message d’erreur est supprimé. La figure 6-2 montre l’objet LoginView dans l’application mobile eShopOnContainers lorsque des erreurs de validation sont présentes.

Affichage des erreurs de validation lors de la connexion

Figure 6-2 : Affichage des erreurs de validation lors de la connexion

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

Le LineColorBehavior comportement attaché est utilisé pour mettre en évidence Entry les contrôles où des erreurs de validation se sont produites. L’exemple de code suivant montre comment le LineColorBehavior comportement attaché est attaché à un Entry contrôle :

<Entry Text="{Binding UserName.Value, Mode=TwoWay}">
    <Entry.Style>
        <OnPlatform x:TypeArguments="Style">
            <On Platform="iOS, Android" Value="{StaticResource EntryStyle}" />
            <On Platform="UWP" Value="{StaticResource UwpEntryStyle}" />
        </OnPlatform>
    </Entry.Style>
    ...
</Entry>

Le Entry contrôle utilise un style explicite, illustré dans l’exemple de code suivant :

<Style x:Key="EntryStyle"  
       TargetType="{x:Type Entry}">  
    ...  
    <Setter Property="behaviors:LineColorBehavior.ApplyLineColor"  
            Value="True" />  
    <Setter Property="behaviors:LineColorBehavior.LineColor"  
            Value="{StaticResource BlackColor}" />  
    ...  
</Style>

Ce style définit les ApplyLineColor LineColor propriétés et les propriétés jointes du LineColorBehavior comportement attaché sur le Entry contrôle. Pour plus d’informations sur les styles, consultez Styles.

Lorsque la valeur de la ApplyLineColor propriété jointe est définie ou change, le LineColorBehavior comportement attaché exécute la OnApplyLineColorChanged méthode, qui est illustrée dans l’exemple de code suivant :

public static class LineColorBehavior  
{  
    ...  
    private static void OnApplyLineColorChanged(  
                BindableObject bindable, object oldValue, object newValue)  
    {  
        var view = bindable as View;  
        if (view == null)  
        {  
            return;  
        }  

        bool hasLine = (bool)newValue;  
        if (hasLine)  
        {  
            view.Effects.Add(new EntryLineColorEffect());  
        }  
        else  
        {  
            var entryLineColorEffectToRemove =   
                    view.Effects.FirstOrDefault(e => e is EntryLineColorEffect);  
            if (entryLineColorEffectToRemove != null)  
            {  
                view.Effects.Remove(entryLineColorEffectToRemove);  
            }  
        }  
    }  
}

Les paramètres de cette méthode fournissent l’instance du contrôle auquel le comportement est attaché, ainsi que les anciennes et nouvelles valeurs de la ApplyLineColor propriété jointe. La EntryLineColorEffect classe est ajoutée à la collection du Effects contrôle si la ApplyLineColor propriété jointe est , sinon elle est truesupprimée de la collection du Effects contrôle. Pour plus d’informations sur les comportements, consultez Implémentation de comportements.

La EntryLineColorEffect sous-classe de la RoutingEffect classe est illustrée dans l’exemple de code suivant :

public class EntryLineColorEffect : RoutingEffect  
{  
    public EntryLineColorEffect() : base("eShopOnContainers.EntryLineColorEffect")  
    {  
    }  
}

La RoutingEffect classe représente un effet indépendant de la plateforme qui encapsule un effet interne spécifique à la plateforme. Cela simplifie le processus de suppression de l’effet, car il n’y a pas d’accès au moment de la compilation aux informations de type pour un effet propre à la plateforme. L’appel EntryLineColorEffect du constructeur de classe de base, en passant un paramètre constitué d’une concaténation du nom du groupe de résolution et de l’ID unique spécifié sur chaque classe d’effet spécifique à la plateforme.

L’exemple de code suivant montre l’implémentation eShopOnContainers.EntryLineColorEffect pour iOS :

[assembly: ResolutionGroupName("eShopOnContainers")]  
[assembly: ExportEffect(typeof(EntryLineColorEffect), "EntryLineColorEffect")]  
namespace eShopOnContainers.iOS.Effects  
{  
    public class EntryLineColorEffect : PlatformEffect  
    {  
        UITextField control;  

        protected override void OnAttached()  
        {  
            try  
            {  
                control = Control as UITextField;  
                UpdateLineColor();  
            }  
            catch (Exception ex)  
            {  
                Console.WriteLine("Can't set property on attached control. Error: ", ex.Message);  
            }  
        }  

        protected override void OnDetached()  
        {  
            control = null;  
        }  

        protected override void OnElementPropertyChanged(PropertyChangedEventArgs args)  
        {  
            base.OnElementPropertyChanged(args);  

            if (args.PropertyName == LineColorBehavior.LineColorProperty.PropertyName ||  
                args.PropertyName == "Height")  
            {  
                Initialize();  
                UpdateLineColor();  
            }  
        }  

        private void Initialize()  
        {  
            var entry = Element as Entry;  
            if (entry != null)  
            {  
                Control.Bounds = new CGRect(0, 0, entry.Width, entry.Height);  
            }  
        }  

        private void UpdateLineColor()  
        {  
            BorderLineLayer lineLayer = control.Layer.Sublayers.OfType<BorderLineLayer>()  
                                                             .FirstOrDefault();  

            if (lineLayer == null)  
            {  
                lineLayer = new BorderLineLayer();  
                lineLayer.MasksToBounds = true;  
                lineLayer.BorderWidth = 1.0f;  
                control.Layer.AddSublayer(lineLayer);  
                control.BorderStyle = UITextBorderStyle.None;  
            }  

            lineLayer.Frame = new CGRect(0f, Control.Frame.Height-1f, Control.Bounds.Width, 1f);  
            lineLayer.BorderColor = LineColorBehavior.GetLineColor(Element).ToCGColor();  
            control.TintColor = control.TextColor;  
        }  

        private class BorderLineLayer : CALayer  
        {  
        }  
    }  
}

La OnAttached méthode récupère le contrôle natif du Xamarin.FormsEntry contrôle et met à jour la couleur de ligne en appelant la UpdateLineColor méthode. Le OnElementPropertyChanged remplacement répond aux modifications de propriété pouvant être liées sur le Entry contrôle en mettant à jour la couleur de ligne si la propriété jointe LineColor change ou la Height propriété des Entry modifications. Pour plus d’informations sur les effets, consultez Effets.

Lorsque les données valides sont entrées dans le Entry contrôle, elles appliquent une ligne noire au bas du contrôle pour indiquer qu’il n’y a aucune erreur de validation. La figure 6-3 montre un exemple de ceci.

Ligne noire indiquant aucune erreur de validation

Figure 6-3 : Ligne noire indiquant aucune erreur de validation

Le Entry contrôle a également ajouté DataTrigger à sa Triggers collection. L’exemple de code suivant montre les DataTriggeréléments suivants :

<Entry Text="{Binding UserName.Value, Mode=TwoWay}">  
    ...  
    <Entry.Triggers>  
        <DataTrigger   
            TargetType="Entry"  
            Binding="{Binding UserName.IsValid}"  
            Value="False">  
            <Setter Property="behaviors:LineColorBehavior.LineColor"   
                    Value="{StaticResource ErrorColor}" />  
        </DataTrigger>  
    </Entry.Triggers>  
</Entry>

Cela DataTrigger surveille la UserName.IsValid propriété et, si sa valeur devient false, elle exécute le Setter, qui modifie la LineColor propriété jointe du LineColorBehavior comportement attaché en rouge. La figure 6-4 montre un exemple de ceci.

Ligne rouge indiquant l’erreur de validation

Figure 6-4 : Ligne rouge indiquant l’erreur de validation

La ligne du Entry contrôle reste rouge alors que les données entrées ne sont pas valides. Sinon, elle passe en noir pour indiquer que les données entrées sont valides.

Pour plus d’informations sur les déclencheurs, consultez Déclencheurs.

Affichage des 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 comment Label afficher 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}" />

Chacune Label est liée à la Errors propriété de l’objet de modèle d’affichage en cours de validation. La propriété Errors est fournie par la classe ValidatableObject<T> et est de type List<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 mobile eShopOnContainers 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 pourquoi 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 Validate méthode de l’instance ValidatableObject<T> , qui récupère les règles de validation et les exécute sur la ValidatableObject<T> Value propriété. Toutes les erreurs de validation sont placées dans la Errors propriété de l’instance ValidatableObject<T>et la IsValid propriété de l’instance ValidatableObject<T> est mise à jour pour indiquer si la validation a réussi ou échoué.