Partilhar via


Validação

Gorjeta

Este conteúdo é um excerto do eBook, Enterprise Application Patterns Using .NET MAUI, disponível no .NET Docs ou como um PDF para download gratuito que pode ser lido offline.

Padrões de aplicativos corporativos usando a miniatura da capa do eBook .NET MAUI .

Qualquer aplicativo que aceite entrada de usuários deve garantir que a entrada seja válida. Um aplicativo pode, por exemplo, verificar se há entradas que contenham apenas caracteres em um intervalo específico, tenham um determinado comprimento ou correspondam a um formato específico. Sem validação, um usuário pode fornecer dados que fazem com que o aplicativo falhe. A validação adequada impõe regras de negócios e pode ajudar a impedir que um invasor injete dados mal-intencionados.

No contexto do padrão Model-View-ViewModel (MVVM), um modelo ou modelo de exibição geralmente será necessário para executar a validação de dados e sinalizar quaisquer erros de validação para a exibição para que o usuário possa corrigi-los. O aplicativo multiplataforma eShop executa a validação síncrona do lado do cliente das propriedades do modelo de exibição e notifica o usuário sobre quaisquer erros de validação, destacando o controle que contém os dados inválidos e exibindo mensagens de erro que informam o usuário sobre por que os dados são inválidos. A imagem abaixo mostra as classes envolvidas na realização da validação no aplicativo multiplataforma eShop.

Aulas de validação na aplicação multiplataforma eShop.

As propriedades do modelo de exibição que exigem validação são do tipo ValidatableObject<T>, e cada ValidatableObject<T> instância tem regras de validação adicionadas à sua Validations propriedade. A validação é invocada a partir do modelo de exibição chamando o Validate método da instância, que recupera as regras de ValidatableObject<T> validação e as executa na ValidatableObject<T>.Value propriedade. Quaisquer erros de validação são colocados na Errors propriedade da ValidatableObject<T> instância e a IsValid propriedade da ValidatableObject<T> instância é atualizada para indicar se a validação foi bem-sucedida ou falhou. O código a seguir mostra a implementação do 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;
    }
}

A notificação de alteração de propriedade é fornecida pela ObservableObject classe e, portanto, um Entry controle pode se vincular à IsValid propriedade de instância na classe de modelo de exibição para ser notificado se os dados inseridos ValidatableObject<T> são válidos ou não.

Especificando regras de validação

As regras de validação são especificadas criando uma classe que deriva da IValidationRule<T> interface, que é mostrada no exemplo de código a seguir:

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

Essa interface especifica que uma classe de regra de validação deve fornecer um método booleano Check que é usado para executar a validação necessária e uma ValidationMessage propriedade cujo valor é a mensagem de erro de validação que será exibida se a validação falhar.

O exemplo de código a seguir mostra a regra de validação IsNotNullOrEmptyRule<T> , que é usada para executar a validação do nome de usuário e senha inseridos pelo usuário no LoginView ao usar serviços simulados no aplicativo multiplataforma eShop:

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

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

O Check método retorna um booleano indicando se o argumento value é nulo, vazio ou consiste apenas em caracteres de espaço em branco.

Embora não seja usado pelo aplicativo multiplataforma eShop, o exemplo de código a seguir mostra uma regra de validação para validar endereços de 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);
}

O Check método retorna um booleano indicando se o argumento value é ou não um endereço de email válido. Isso é conseguido pesquisando o argumento value para a primeira ocorrência do padrão de expressão regular especificado no Regex construtor. Se o padrão de expressão regular foi encontrado na cadeia de caracteres de entrada pode ser determinado verificando o value contra Regex.IsMatch.

Nota

Às vezes, a validação de propriedade pode envolver propriedades dependentes. Um exemplo de propriedades dependentes é quando o conjunto de valores válidos para a propriedade A depende do valor específico que foi definido na propriedade B. Para verificar se o valor da propriedade A é um dos valores permitidos envolveria recuperar o valor da propriedade B. Além disso, quando o valor do imóvel B muda, o imóvel A precisa ser revalidado.

Adicionando regras de validação a uma propriedade

No aplicativo multiplataforma eShop, as propriedades do modelo de exibição que exigem validação são declaradas como do tipo ValidatableObject<T>, onde T é o tipo dos dados a serem validados. O exemplo de código a seguir mostra um exemplo de duas dessas propriedades:

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

Para que a validação ocorra, as regras de validação devem ser adicionadas à coleção Validations de cada ValidatableObject<T> instância, conforme demonstrado no exemplo de código a seguir:

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

Esse método adiciona a IsNotNullOrEmptyRule<T> regra de validação à Validations coleção de cada ValidatableObject<T> instância, especificando valores para a propriedade da ValidationMessage regra de validação, que especifica a mensagem de erro de validação que será exibida se a validação falhar.

Acionando a validação

A abordagem de validação usada no aplicativo multiplataforma eShop pode acionar manualmente a validação de uma propriedade e acionar automaticamente a validação quando uma propriedade é alterada.

Acionando a validação manualmente

A validação pode ser acionada manualmente para uma propriedade de modelo de exibição. Por exemplo, isso ocorre no aplicativo multiplataforma eShop quando o usuário toca Login no botão no LoginView, ao usar serviços simulados. O delegado de comando chama o MockSignInAsync método no LoginViewModel, que invoca a validação executando o Validate método, que é mostrado no exemplo de código a seguir:

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

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

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

O Validate método executa a validação do nome de usuário e senha inseridos pelo usuário no LoginView, invocando o Validate método em cada ValidatableObject<T> instância. O exemplo de código a seguir mostra o Validate método da ValidatableObject<T> classe:

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

    IsValid = !Errors.Any();

    return IsValid;
}

Esse método recupera todas as regras de validação que foram adicionadas à coleção do Validations objeto. O Check método para cada regra de validação recuperada é executado e o valor da ValidationMessage propriedade para qualquer regra de validação que não consegue validar os dados é adicionado à Errors coleção da ValidatableObject<T> instância. Finalmente, a IsValid propriedade é definida e seu valor é retornado para o método de chamada, indicando se a validação foi bem-sucedida ou falhou.

Acionando a validação quando as propriedades são alteradas

A validação também é acionada automaticamente sempre que uma propriedade vinculada é alterada. Por exemplo, quando uma ligação bidirecional no define a propriedade orPassword, a LoginView UserName validação é acionada. O exemplo de código a seguir demonstra como isso ocorre:

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

O Entry controle se liga à UserName.Value propriedade da ValidatableObject<T> instância e a coleção do Behaviors controle tem uma EventToCommandBehavior instância adicionada a ela. Esse comportamento executa o ValidateUserNameCommand em resposta ao disparo TextChanged de evento no Entry, que é gerado quando o texto nas Entry alterações. Por sua vez, o ValidateUserNameCommand delegado executa o ValidateUserName método, que executa o Validate método na ValidatableObject<T> instância. Portanto, toda vez que o usuário insere um caractere no Entry controle para o nome de usuário, a validação dos dados inseridos é executada.

Exibindo erros de validação

O aplicativo multiplataforma eShop notifica o usuário de quaisquer erros de validação, destacando o controle que contém os dados inválidos com um fundo vermelho e exibindo uma mensagem de erro que informa o usuário por que os dados são inválidos abaixo do controle que contém os dados inválidos. Quando os dados inválidos são corrigidos, o plano de fundo muda de volta para o estado padrão e a mensagem de erro é removida. A imagem abaixo mostra o LoginView no aplicativo multiplataforma eShop quando erros de validação estão presentes.

Exibição de erros de validação durante o login.

Realçando um controle que contém dados inválidos

O .NET MAUI oferece várias maneiras de apresentar informações de validação aos usuários finais, mas uma das maneiras mais diretas é por meio do uso do Triggers. Triggers Fornecer-nos uma maneira de alterar o estado de nossos controles, normalmente para aparência, com base em um evento ou alteração de dados que ocorre para um controle. Para a validação, usaremos um DataTrigger que ouvirá as alterações geradas de uma propriedade vinculada e responderá às alterações. Os Entry controles na LoginView configuração são usando o seguinte código:

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

O DataTrigger especifica as seguintes propriedades:

Property Description
TargetType O tipo de controle ao qual o gatilho pertence.
Binding A marcação de dados Binding que fornecerá notificações de alteração e valor para a condição de gatilho.
Value O valor de dados para especificar quando a condição do gatilho foi atendida.

Para isso Entry, estaremos atentos às alterações ao LoginViewModel.UserName.IsValid imóvel. Cada vez que essa propriedade gerar uma alteração, o valor será comparado com a Value propriedade definida no DataTrigger. Se os valores forem iguais, a condição de gatilho DataTrigger será atendida e todos os Setter objetos fornecidos ao serão executados. Esse controle tem um único Setter objeto que atualiza a BackgroundColor propriedade para uma cor personalizada definida usando a StaticResource marcação. Quando uma Trigger condição não for mais atendida, o controle reverterá as propriedades definidas pelo Setter objeto para seu estado anterior. Para obter mais informações sobre Triggerso , consulte .NET MAUI Docs: Triggers.

A apresentar mensagens de erro

A interface do usuário exibe mensagens de erro de validação em controles Label abaixo de cada controle cujos dados falharam na validação. O exemplo de código a seguir mostra o Label que exibe uma mensagem de erro de validação, se o usuário não tiver inserido um nome de usuário válido:

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

Cada Label se liga à Errors propriedade do objeto de modelo de exibição que está sendo validado. A Errors propriedade é fornecida pela ValidatableObject<T> classe, e é do tipo IEnumerable<string>. Como a Errors propriedade pode conter vários erros de validação, a FirstValidationErrorConverter instância é usada para recuperar o primeiro erro da coleção para exibição.

Resumo

O aplicativo multiplataforma eShop executa a validação síncrona do lado do cliente das propriedades do modelo de exibição e notifica o usuário sobre quaisquer erros de validação, destacando o controle que contém os dados inválidos e exibindo mensagens de erro que informam o usuário por que os dados são inválidos.

As propriedades do modelo de exibição que exigem validação são do tipo ValidatableObject<T>, e cada ValidatableObject<T> instância tem regras de validação adicionadas à sua Validations propriedade. A validação é invocada a partir do modelo de exibição chamando o Validate método da instância, que recupera as regras de ValidatableObject<T> validação e as executa na ValidatableObject<T> propriedade Value. Quaisquer erros de validação são colocados na propriedade da ValidatableObject<T> instância e a propriedade IsValid da instância é atualizada para indicar se a Errors ValidatableObject<T> validação foi bem-sucedida ou falhou.