Validierung in Unternehmens-Apps

Hinweis

Dieses eBook wurde im Frühjahr 2017 veröffentlicht und wurde seitdem nicht aktualisiert. Es gibt vieles im Buch, das wertvoll bleibt, aber ein Teil des Materials ist veraltet.

Jede App, die Eingaben von Benutzern akzeptiert, sollte sicherstellen, dass die Eingabe gültig ist. Eine App könnte beispielsweise auf Eingaben prüfen, die nur Zeichen in einem bestimmten Bereich enthalten, eine bestimmte Länge haben oder einem bestimmten Format entsprechen. Ohne Validierung kann ein Benutzer Daten bereitstellen, die dazu führen, dass die App fehlschlägt. Die Überprüfung erzwingt Geschäftsregeln und verhindert, dass angreifer böswillige Daten einschleusen.

Im Kontext des MVVM-Musters (Model-View-ViewModel) ist häufig ein Ansichtsmodell oder Modell erforderlich, um die Datenvalidierung durchzuführen und alle Validierungsfehler an die Ansicht zu melden, damit der Benutzer sie korrigieren kann. Die mobile eShopOnContainers-App führt eine synchrone clientseitige Überprüfung der Eigenschaften des Ansichtsmodells durch und benachrichtigt den Benutzer über validierungsfehler, indem das Steuerelement hervorgehoben wird, das die ungültigen Daten enthält, und Fehlermeldungen angezeigt werden, die den Benutzer darüber informieren, warum die Daten ungültig sind. Abbildung 6-1 zeigt die Klassen, die an der Überprüfung in der mobilen eShopOnContainers-App beteiligt sind.

Validierungsklassen in der mobilen eShopOnContainers-App

Abbildung 6-1: Validierungsklassen in der mobilen eShopOnContainers-App

Ansichtsmodelleigenschaften, die eine Validierung erfordern, sind vom Typ ValidatableObject<T>, und jede ValidatableObject<T>-Instanz verfügt über Validierungsregeln, die ihrer Validations-Eigenschaft hinzugefügt wurden. Die Überprüfung wird über das Ansichtsmodell aufgerufen, indem die Validate Methode des ValidatableObject<T> instance aufgerufen wird, die die Validierungsregeln abruft und für die ValidatableObject<T>Value -Eigenschaft ausführt. Alle Validierungsfehler werden in die Errors Eigenschaft des ValidatableObject<T> instance eingefügt, und die IsValid Eigenschaft des instance wird aktualisiert, um anzugeben, ob die ValidatableObject<T> Überprüfung erfolgreich war oder fehlgeschlagen ist.

Eigenschaftsänderungsbenachrichtigungen werden von der ExtendedBindableObject-Klasse bereitgestellt. Daher kann ein Entry-Steuerelement an die IsValidEigenschaft der ValidatableObject<T>-Instanz in der Ansichtsmodellklasse gebunden werden, um benachrichtigt zu werden, ob die eingegebenen Daten gültig sind.

Angeben von Validierungsregeln

Validierungsregeln werden durch Erstellen einer Klasse angegeben, die von der IValidationRule<T>-Schnittstelle abgeleitet wird, was im folgenden Codebeispiel gezeigt wird:

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

Diese Schnittstelle gibt an, dass eine Validierungsregelklasse eine booleanCheck Methode bereitstellen muss, die zum Ausführen der erforderlichen Überprüfung verwendet wird, und eine ValidationMessage Eigenschaft, deren Wert die Validierungsfehlermeldung ist, die angezeigt wird, wenn die Überprüfung fehlschlägt.

Das folgende Codebeispiel zeigt die Validierungsregel IsNotNullOrEmptyRule<T> , die verwendet wird, um die Überprüfung des Benutzernamens und Des Kennworts durchzuführen, der vom Benutzer für die LoginView Verwendung von Pseudodiensten in der mobilen eShopOnContainers-App eingegeben wird:

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);  
    }  
}

Die Check -Methode gibt einen boolean zurück, der angibt, ob das Wertargument leer ist nulloder nur aus Leerzeichen besteht.

Obwohl nicht von der mobilen eShopOnContainers-App verwendet, zeigt das folgende Codebeispiel eine Validierungsregel zum Überprüfen von E-Mail-Adressen:

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

Die Check -Methode gibt einen boolean zurück, der angibt, ob das Wertargument eine gültige E-Mail-Adresse ist. Dies wird erreicht, indem das Wertargument nach dem ersten Vorkommen des im Regex-Konstruktor angegebenen Musters für reguläre Ausdrücke durchsucht wird. Ob das Muster des regulären Ausdrucks in der Eingabezeichenfolge gefunden wurde, kann durch Überprüfen des Werts der -Eigenschaft des MatchSuccess Objekts bestimmt werden.

Hinweis

Die Validierung von Eigenschaften kann manchmal abhängige Eigenschaften umfassen. Ein Beispiel für abhängige Eigenschaften ist, wenn die Menge der gültigen Werte für Eigenschaft A von dem bestimmten Wert abhängt, der in Eigenschaft B festgelegt wurde. Um zu prüfen, ob der Wert von Eigenschaft A einer der zulässigen Werte ist, müsste der Wert von Eigenschaft B abgerufen werden. Wenn sich der Wert von Eigenschaft B ändert, müsste außerdem die Eigenschaft A erneut validiert werden.

Hinzufügen von Validierungsregeln zu einer Eigenschaft

In der mobilen eShopOnContainers-App werden die Modelleigenschaften, die eine Überprüfung erfordern, als vom Typ ValidatableObject<T>deklariert, wobei T der Typ der zu überprüfenden Daten ist. Das folgende Codebeispiel zeigt ein Beispiel für zwei solcher Eigenschaften:

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

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

Damit die Überprüfung durchgeführt wird, müssen der Validations Auflistung jeder ValidatableObject<T> instance Überprüfungsregeln hinzugefügt werden, wie im folgenden Codebeispiel veranschaulicht:

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."   
    });  
}

Diese Methode fügt die IsNotNullOrEmptyRule<T>-Validierungsregel der Validations-Sammlung jeder ValidatableObject<T>-Instanz hinzu und gibt Werte für die ValidationMessage-Eigenschaft der Validierungsregel an, die die Validierungsfehlermeldung angibt, die angezeigt wird, wenn die Validierung fehlschlägt.

Auslösen der Überprüfung

Der in der mobilen eShopOnContainers-App verwendete Validierungsansatz kann die Überprüfung einer Eigenschaft manuell auslösen und automatisch die Überprüfung auslösen, wenn sich eine Eigenschaft ändert.

Manuelles Auslösen der Überprüfung

Validierung kann manuell für eine Ansichtsmodelleigenschaft ausgelöst werden. Dies tritt beispielsweise in der mobilen eShopOnContainers-App auf, wenn der Benutzer bei Verwendung von Pseudodiensten auf die LoginViewSchaltfläche Anmeldung tippen. Der Befehlsdelegat ruft die MockSignInAsync-Methode im LoginViewModel auf, wodurch die Validierung durch Ausführen der Validate-Methode aufgerufen wird.Dies wird im folgenden Codebeispiel gezeigt:

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

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

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

Die Validate -Methode führt die Überprüfung des Benutzernamens und des Kennworts durch, der vom Benutzer für den LoginVieweingegeben wurde, indem die Validate-Methode für jeden ValidatableObject<T> instance aufgerufen wird. Das folgende Codebeispiel zeigt die Validate-Methode aus der ValidatableObject<T> -Klasse:

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

Diese Methode löscht die Errors Auflistung und ruft dann alle Validierungsregeln ab, die der Auflistung des Validations Objekts hinzugefügt wurden. Die Check-Methode für jede abgerufene Validierungsregel wird ausgeführt, und der Wert der ValidationMessage-Eigenschaft für jede Validierungsregel, die die Daten nicht validieren kann, wird der Errors-Sammlung der ValidatableObject<T>-Instanz hinzugefügt. Schließlich wird die IsValid-Eigenschaft festgelegt, und ihr Wert wird an die aufrufende Methode zurückgegeben. Dieser Wert gibt an, ob die Validierung erfolgreich war oder fehlgeschlagen ist.

Auslösen der Überprüfung bei Änderung der Eigenschaften

Die Überprüfung kann auch ausgelöst werden, wenn sich eine gebundene Eigenschaft ändert. Wenn eine bidirektionale Bindung beispielsweise in der LoginView die UserName- oder Password-Eigenschaft festlegt, wird Validierung ausgelöst. Das folgende Codebeispiel veranschaulicht, wie dies erreicht wird:

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

Das Entry-Steuerelement wird an die UserName.Value-Eigenschaft der ValidatableObject<T>-Instanz gebunden, und der Behaviors-Sammlung des Steuerelements wird eine EventToCommandBehavior-Instanz hinzugefügt. Dieses Verhalten führt das als Antwort auf das ValidateUserNameCommand [TextChanged]-Ereignis aus, das auf Entryausgelöst wird, wenn sich der Text in der Entry ändert. Der ValidateUserNameCommand-Delegat wiederum führt die ValidateUserName-Methode aus, die die Validate-Methode für die ValidatableObject<T>-Instanz ausführt. Daher wird jedes Mal, wenn der Benutzer ein Zeichen in das Entry-Steuerelement für den Benutzernamen eingibt, eine Validierung der eingegebenen Daten durchgeführt.

Weitere Informationen zu Verhaltensweisen finden Sie unter Implementieren von Verhaltensweisen.

Anzeigen von Validierungsfehlern

Die mobile eShopOnContainers-App benachrichtigt den Benutzer über validierungsfehler, indem das Steuerelement, das die ungültigen Daten enthält, mit einer roten Linie hervorgehoben wird, und eine Fehlermeldung angezeigt wird, die den Benutzer darüber informiert, warum die Daten unterhalb des Steuerelements ungültig sind, das die ungültigen Daten enthält. Wenn die ungültigen Daten korrigiert werden, ändert sich die Zeile in schwarz, und die Fehlermeldung wird entfernt. Abbildung 6-2 zeigt die LoginView in der mobilen eShopOnContainers-App, wenn Validierungsfehler vorliegen.

Anzeigen von Validierungsfehlern während der Anmeldung

Abbildung 6-2: Anzeigen von Validierungsfehlern während der Anmeldung

Hervorheben eines Steuerelements, das ungültige Daten enthält

Das LineColorBehavior angefügte Verhalten wird verwendet, um Steuerelemente hervorzuheben Entry , bei denen Validierungsfehler aufgetreten sind. Das folgende Codebeispiel zeigt, wie das LineColorBehavior angefügte Verhalten an ein Entry Steuerelement angefügt wird:

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

Das Entry Steuerelement verwendet eine explizite Formatvorlage, die im folgenden Codebeispiel gezeigt wird:

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

Diese Formatvorlage legt die und LineColor die ApplyLineColor angefügten Eigenschaften des LineColorBehavior angefügten Verhaltens für das Entry Steuerelement fest. Weitere Informationen zu Formatvorlagen finden Sie unter Styles (Formatvorlagen).

Wenn der Wert der ApplyLineColor angefügten Eigenschaft festgelegt oder geändert wird, führt das LineColorBehavior angefügte Verhalten die OnApplyLineColorChanged -Methode aus, was im folgenden Codebeispiel gezeigt wird:

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);  
            }  
        }  
    }  
}

Die Parameter für diese Methode bieten die instance des Steuerelements, an das das Verhalten angefügt ist, sowie die alten und neuen Werte der ApplyLineColor angefügten Eigenschaft. Die EntryLineColorEffect -Klasse wird der Auflistung des Steuerelements Effects hinzugefügt, wenn die ApplyLineColor angefügte Eigenschaft ist true, andernfalls wird sie aus der Auflistung des Steuerelements Effects entfernt. Weitere Informationen zu Verhaltensweisen finden Sie unter Implementieren von Verhaltensweisen.

Die EntryLineColorEffect Unterklassen der RoutingEffect -Klasse werden im folgenden Codebeispiel dargestellt:

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

Die RoutingEffect -Klasse stellt einen plattformunabhängigen Effekt dar, der einen inneren Effekt umschließt, der plattformspezifisch ist. Dadurch wird das Entfernen eines Effekts vereinfacht, da während der Kompilierzeit nicht auf die Typinformationen für einen plattformspezifischen Effekt zugegriffen werden kann. Ruft EntryLineColorEffect den Basisklassenkonstruktor auf und übergibt einen Parameter, der aus einer Verkettung des Auflösungsgruppennamens und der eindeutigen ID besteht, die für jede plattformspezifische Effektklasse angegeben ist.

Das folgende Codebeispiel zeigt die eShopOnContainers.EntryLineColorEffect Implementierung für 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  
        {  
        }  
    }  
}

Die OnAttached -Methode ruft das systemeigene Steuerelement für das Xamarin.FormsEntry Steuerelement ab und aktualisiert die Linienfarbe durch Aufrufen der UpdateLineColor -Methode. Die OnElementPropertyChanged Überschreibung reagiert auf änderungen der bindungsfähigen Eigenschaft am Entry Steuerelement, indem die Linienfarbe aktualisiert wird, wenn sich die angefügte LineColor Eigenschaft ändert, oder die Height Eigenschaft der Entry Änderungen. Weitere Informationen zu Effekten finden Sie unter Effekte.

Wenn gültige Daten in das Entry Steuerelement eingegeben werden, wird eine schwarze Linie auf den unteren Rand des Steuerelements angewendet, um anzugeben, dass kein Validierungsfehler vorliegt. Abbildung 6-3 zeigt ein Beispiel dafür.

Schwarze Linie, die keinen Validierungsfehler anzeigt

Abbildung 6-3: Schwarze Linie, die keinen Validierungsfehler anzeigt

Das Entry Steuerelement hat seiner Auflistung auch eine DataTrigger hinzugefügt Triggers . Das folgende Codebeispiel zeigt folgendes 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>

Dadurch DataTrigger wird die UserName.IsValid -Eigenschaft überwacht, und wenn der Wert zu falsewird, wird der Setterausgeführt, wodurch die LineColor angefügte Eigenschaft des LineColorBehavior angefügten Verhaltens in Rot geändert wird. Abbildung 6-4 zeigt ein Beispiel dafür.

Rote Linie, die einen Validierungsfehler anzeigt

Abbildung 6-4: Rote Linie, die einen Validierungsfehler anzeigt

Die Zeile im Entry Steuerelement bleibt rot, während die eingegebenen Daten ungültig sind, andernfalls wird sie in Schwarz geändert, um anzugeben, dass die eingegebenen Daten gültig sind.

Weitere Informationen zu Triggern finden Sie unter Trigger.

Anzeigen von Fehlermeldungen

Die Benutzeroberfläche zeigt Validierungsfehlermeldungen in Label-Steuerelementen unter jedem Steuerelement an, dessen Daten die Validierung nicht bestanden haben. Das folgende Codebeispiel zeigt, Label dass eine Überprüfungsfehlermeldung anzeigt, wenn der Benutzer keinen gültigen Benutzernamen eingegeben hat:

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

Jede Label Bindung an die Errors Eigenschaft des Zuschaumodellobjekts, das überprüft wird. Die Errors-Eigenschaft wird von der ValidatableObject<T>-Klasse bereitgestellt und ist vom Typ List<string>. Da die Errors-Eigenschaft mehrere Validierungsfehler enthalten kann, wird die FirstValidationErrorConverter-Instanz verwendet, um den ersten Fehler aus der Sammlung zur Anzeige abzurufen.

Zusammenfassung

Die mobile eShopOnContainers-App führt eine synchrone clientseitige Überprüfung der Ansichtsmodelleigenschaften durch und benachrichtigt den Benutzer über überprüfungsfehler, indem das Steuerelement hervorgehoben wird, das die ungültigen Daten enthält, und Fehlermeldungen angezeigt werden, die den Benutzer darüber informieren, warum die Daten ungültig sind.

Ansichtsmodelleigenschaften, die eine Validierung erfordern, sind vom Typ ValidatableObject<T>, und jede ValidatableObject<T>-Instanz verfügt über Validierungsregeln, die ihrer Validations-Eigenschaft hinzugefügt wurden. Die Validierung wird über das Ansichtsmodell aufgerufen, indem die Validate -Methode der ValidatableObject<T> instance aufgerufen wird, die die Validierungsregeln abruft und für die ValidatableObject<T>Value -Eigenschaft ausführt. Alle Validierungsfehler werden in die Errors Eigenschaft des ValidatableObject<T>instance eingefügt, und die IsValid Eigenschaft des instance wird aktualisiert, um anzugeben, ob die ValidatableObject<T> Überprüfung erfolgreich war oder fehlgeschlagen ist.