Partager via


Validation dans les applications d’entreprise

Notes

Ce livre électronique a été publié au printemps 2017 et n’a pas été mis à jour depuis lors. Il y a beaucoup dans le livre qui reste précieux, mais une partie du matériel 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 d’entreprise 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 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. 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 du ValidatableObject<T> instance, 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é du ValidatableObject<T> instance, et la IsValid propriété du ValidatableObject<T> instance 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 booleanCheck 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 en cas d’échec de la validation.

L’exemple de code suivant montre la IsNotNullOrEmptyRule<T> règle de validation, qui est utilisée pour effectuer la validation du nom d’utilisateur et du mot de passe entrés par l’utilisateur sur le 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 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 valider les 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 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 la valeur de la propriété de l’objet MatchSuccess .

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 mobile eShopOnContainers, afficher les propriétés du modèle qui nécessitent une 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, des 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 en cas de modification d’une propriété.

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 , 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 Validations 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 en cas de modification des propriétés

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 le ValidateUserNameCommand en réponse à l’événement [TextChanged] déclenché sur le Entry, qui est déclenché lorsque le texte dans le 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.

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 toute erreur 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 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, la ligne devient noire et le message d’erreur est supprimé. La figure 6-2 montre loginView dans l’application mobile eShopOnContainers quand 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 surbrillance 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, qui est 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 propriétés et LineColor 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 le 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 true, sinon elle est supprimée de la collection du Effects contrôle. Pour plus d’informations sur les comportements, consultez Implémentation de comportements.

Le EntryLineColorEffect sous-classe la RoutingEffect classe et est illustré 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. Appelle EntryLineColorEffect le 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 des données valides sont entrées dans le Entry contrôle, il applique une ligne noire au bas du contrôle, pour indiquer qu’il n’y a pas d’erreur de validation. La figure 6-3 en montre un exemple.

Ligne noire indiquant aucune erreur de validation

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

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

<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>

Cette DataTrigger opération 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 en montre un exemple.

Ligne rouge indiquant une erreur de validation

Figure 6-4 : Ligne rouge indiquant une erreur de validation

La ligne dans le Entry contrôle reste rouge alors que les données entrées ne sont pas valides. Sinon, elle passe au 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 le 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}" />

Chacune Label est liée à la Errors propriété 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 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 côté client synchrone des propriétés du modèle d’affichage et informe 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.

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 du ValidatableObject<T> instance, 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é du ValidatableObject<T>instance, et la IsValid propriété du ValidatableObject<T> instance est mise à jour pour indiquer si la validation a réussi ou échoué.