validação de formulários no lado do cliente do ASP.NET Core Blazor em SSR estático

Este artigo explica como Blazor adiciona a validação dinâmica do lado do cliente a formulários que usam a renderização estática do lado do servidor (SSR estático). O navegador valida campos individuais à medida que o usuário os edita e valida o formulário completo antes de ser enviado. Se a verificação do lado do cliente for aprovada, o formulário será enviado e validado novamente no servidor.

Os formulários que usam um modo de renderização interativo não usam o recurso de validação estático do lado do cliente SSR descrito neste artigo. Tanto a validação por campo quanto a validação no envio do formulário completo são executadas no .NET por meio do EditContext do formulário.

Como funciona a validação do lado do cliente

Quando um formulário SSR estático contém um DataAnnotationsValidator componente, Blazor renderiza as regras de validação do formulário na página e as impõe usando JavaScript antes que o formulário seja enviado. O usuário vê erros de validação sem precisar enviar uma solicitação ao servidor e aguardar a resposta.

A validação do lado do cliente é ativada automaticamente quando as seguintes condições são atendidas:

Para o conjunto interno de atributos de validação, nenhuma configuração javaScript, pacote adicional ou registro de serviço é necessário. A seção Regras de validação personalizadas do lado do cliente descreve como adicionar suporte a atributos de validação personalizados.

Importante

A validação do lado do cliente é uma melhoria da experiência do usuário, não um passe de validação autoritativa. Ele pode ser ignorado desabilitando ou modificando a execução do JavaScript do navegador. A validação do lado do servidor é executada após a postagem do formulário e permanece autoritativa. Nunca confie na validação do lado do cliente para proteger a integridade dos dados.

Atributos de validação com suporte

Os atributos System.ComponentModel.DataAnnotations a seguir são impostos no lado do cliente, correspondendo ao comportamento de anotações de dados do lado do servidor:

Os atributos de validação que não aparecem nesta lista, incluindo atributos personalizados derivados de ValidationAttribute, não são aplicados no lado do cliente por padrão. Eles continuam sendo executados no servidor após o envio do formulário. Para fornecer uma regra do lado do cliente para um atributo personalizado, consulte a seção Regras de validação personalizadas do lado do cliente .

Tempo de validação

Um campo é validado quando seu valor é confirmado. Para entradas de texto (<input> elementos), isso ocorre quando o campo perde o foco. Caixas de seleção e listas suspensas são validadas imediatamente após a seleção.

Depois que um campo tiver mostrado um erro de validação ou após o formulário ter sido enviado pelo menos uma vez, o campo será validado novamente em cada pressionamento de tecla para que as correções sejam refletidas imediatamente.

Enviar o formulário valida cada campo rastreado. Se qualquer campo for inválido, o envio será bloqueado e o foco será movido para o primeiro campo inválido.

Mensagens de validação, localização e acessibilidade

A validação do lado do cliente usa ValidationMessage<TValue> para exibir mensagens para campos individuais e ValidationSummary para exibir mensagens para todo o formulário, que é a mesma maneira que a validação interativa relata mensagens aos usuários.

Quando a localização de validação é configurada, as mensagens de erro são localizadas no servidor à medida que a página é renderizada, portanto, a validação do lado do cliente exibe as mesmas cadeias de caracteres localizadas que a experiência do lado do servidor. A localização requer Microsoft.Extensions.Validation. Para obter mais informações, consulte Validação no ASP.NET Core.

Os atributos ARIA em campos de entrada e contêineres de mensagens de validação são gerenciados automaticamente por Blazor, portanto as tecnologias assistivas anunciam erros de validação sem necessidade de configuração adicional.

Classes CSS de validação de estado

O mecanismo de validação do lado do cliente aplica as mesmas classes CSS da validação interativa de Blazor, conforme mostrado na tabela a seguir.

Elemento Aulas
Entrada valid ou invalid, mais modified uma vez que o usuário edita o campo
Mensagem de validação validation-message
Resumo da validação validation-summary-errors ou validation-summary-valid

A validação no lado do cliente também usa a API de Validação de Restrições do navegador, assim as pseudoclasses CSS padrão :valid e :invalid refletem o estado atual de validação de cada campo.

Recusar a validação do lado do cliente

O recurso pode ser desabilitado em vários níveis. A validação do lado do servidor não é afetada por nenhuma das opções desta seção.

Optar por um único formulário

Defina o parâmetro DisableClientValidation do componente DataAnnotationsValidator como true:

<DataAnnotationsValidator DisableClientValidation="true" />

Recusar o aplicativo inteiro

Defina DisableClientValidation em Razor quando os serviços do componente RazorComponentsServiceOptions forem registrados no arquivo Program:

builder.Services.AddRazorComponents(options =>
{
    options.DisableClientValidation = true;
});

A opção global tem precedência. Quando definido como true, os formulários não emitem regras de validação do lado do cliente.

Desativar a opção de um único botão de envio

Use o atributo HTML formnovalidate padrão no botão. O formulário é postado sem uma verificação do lado do cliente e a validação do lado do servidor ainda é executada após a postagem:

<button type="submit" formnovalidate>Save draft</button>

Isso pode ser usado para implementar um botão "salvar rascunho" ou "voltar" que não exige um formulário completamente válido para que o envio seja bem-sucedido.

Regras de validação personalizadas do lado do cliente

Os atributos de validação personalizados continuam a ser executados no servidor, mas não têm uma implementação do lado do cliente por padrão. A imposição de uma regra personalizada no navegador envolve duas etapas: emitir a regra do atributo .NET e registrar um validador JavaScript correspondente. A implementação do lado do servidor permanece autoritativa.

Emitir a regra do .NET

Implemente IClientValidationRuleProvider no atributo de validação e retorne uma ou mais ClientValidationRule instâncias. A regra Name identifica o validador do lado do cliente, e Parameters fornece os valores de que o validador precisa.

O seguinte StartsWithAttribute valida no servidor em IsValid e fornece uma regra no lado do cliente em startswith com o parâmetro prefix:

using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Components.Forms;

namespace BlazorSample.Validation;

// A custom validation attribute that also contributes a client-side rule for static SSR
// forms. The rule name ('startswith') must match the validator registered on the client
// with Blazor.formValidation.addValidator.
public sealed class StartsWithAttribute : ValidationAttribute, IClientValidationRuleProvider
{
    private readonly string prefix;

    public StartsWithAttribute(string prefix)
    {
        this.prefix = prefix;
        ErrorMessage = $"The value must start with '{prefix}'.";
    }

    protected override ValidationResult? IsValid(object? value,
        ValidationContext validationContext)
    {
        // Leave empty values to RequiredAttribute, matching the client-side validator.
        if (value is not string text || text.Length == 0)
        {
            return ValidationResult.Success;
        }

        if (!text.StartsWith(prefix, StringComparison.Ordinal))
        {
            return new ValidationResult(ErrorMessage, [validationContext.MemberName!]);
        }

        return ValidationResult.Success;
    }

    public IEnumerable<ClientValidationRule> GetClientValidationRules()
    {
        yield return new ClientValidationRule(
            "startswith",
            new Dictionary<string, string> { ["prefix"] = prefix });
    }
}

Aplique o atributo ao modelo da maneira usual:

using System.ComponentModel.DataAnnotations;

namespace BlazorSample.Validation;

// Model for the static SSR client-side validation sample. The StartsWith attribute
// contributes a client-side rule enforced in the browser before the form is submitted.
public class ShipModel
{
    [Required]
    [StartsWith("NCC-")]
    public string? Registry { get; set; }
}

Registrar o validador JavaScript

No JavaScript, chame Blazor.formValidation.addValidator(name, validator) para associar um nome de regra a uma função de validador. O name deve corresponder exatamente a ClientValidationRule.Name, incluindo maiúsculas e minúsculas. Os registros são válidos para todo o aplicativo, e registrar novamente o mesmo nome substitui o validador anterior.

Aviso

Se nenhum validador JavaScript estiver registrado para um nome de regra emitido, a regra será ignorada no navegador. A validação do lado do servidor ainda é executada quando o formulário é postado.

Registre validadores personalizados apenas uma vez no código de inicialização do aplicativo. Escolha o local de registro com base em como Blazor começa, conforme descrito na tabela a seguir.

Blazor inicialização Local de registro
Inicialização automática (padrão) Um script imediatamente após o blazor.web.js
Manual Blazor.start() A continuação retornada por Blazor.start()
Qualquer um dos estilos de inicialização O callback de afterWebStarted de um inicializador JavaScript

Um inicializador JavaScript funciona com qualquer estilo de inicialização. Em um arquivo nomeado {ASSEMBLY NAME}.lib.module.js na pasta do wwwroot aplicativo:

// A JavaScript initializer works with automatic or manual Blazor startup. The validation service
// is available when afterWebStarted runs, even if the current page contains no validated form.
export function afterWebStarted(blazor) {
  blazor.formValidation.addValidator('startswith', (context) => {
    const value = context.value;

    // An empty value is valid. Use [Required] to require a value.
    if (!value) {
      return { success: true };
    }

    return { success: value.startsWith(context.params.prefix) };
  });
}

Com a inicialização automática, um script de validador específico do aplicativo pode ser carregado imediatamente após blazor.web.js:

<script src="@Assets["_framework/blazor.web.js"]"></script>
<script src="@Assets["js/custom-validation.js"]"></script>

O segundo script pode chamar Blazor.formValidation.addValidator diretamente.

Com a inicialização manual, defina o registro em um script de aplicativo:

function registerCustomValidators(blazor) {
  blazor.formValidation.addValidator('startswith', (context) => {
    const value = context.value;

    if (!value) {
      return { success: true };
    }

    return { success: value.startsWith(context.params.prefix) };
  });
}

// Automatic startup initializes formValidation before this script runs.
// Manual startup calls registerCustomValidators after Blazor.start completes.
if (Blazor.formValidation) {
  registerCustomValidators(Blazor);
}

Carregue os scripts com a inicialização automática desabilitada e registre os validadores após a conclusão de Blazor.start():

<script src="@Assets["_framework/blazor.web.js"]" autostart="false"></script>
<script src="@Assets["js/custom-validation.js"]"></script>
<script>
    Blazor.start().then(() => {
        registerCustomValidators(Blazor);
    });
</script>

Importante

Registre validadores do código de inicialização do aplicativo, não de um componente de página ou formulário. Um script do componente pode ser executado antes de Blazor ser iniciado, e os scripts adicionados pela navegação aprimorada não são executados. Os componentes SSR estáticos também não podem ser usados IJSRuntime porque não têm um runtime de .NET interativo.

Gravar funções de validador JavaScript

O validador recebe um objeto de contexto com os membros a seguir, conforme mostrado na tabela a seguir.

Membro Description
value O valor atual do campo como uma cadeia de caracteres ou null/undefined quando não há valor.
element O elemento select, textarea ou input validado.
params A regra é como um dicionário de Parameters cadeia de caracteres.

Espera-se que o validador retorne { success: true } quando o valor for válido. Retorne { success: false } para usar a mensagem da regra fornecida pelo servidor, ou você pode retornar { success: false, message: '...' } para substituir a mensagem nessa chamada.

Os valores vazios normalmente devem ser tratados como válidos por regras que não sejam required, permitindo que um campo opcional permaneça vazio e, ainda assim, validar os valores fornecidos.

Implemente a mesma semântica de regra em .NET e JavaScript, incluindo diferenciação de maiúsculas e minúsculas, normalização e manipulação de valor vazio. Se as implementações forem diferentes, o navegador e a validação autoritativa do lado do servidor poderão produzir resultados diferentes.

Validar formulário quando necessário

A Blazor.formValidation API também expõe métodos JavaScript para validação sob demanda, como mostra a tabela a seguir.

Método Description
validateField(element) Valida um único elemento de campo e atualiza sua exibição de erro. Retorna true quando válido.
validateForm(form) Valida cada campo rastreado em um formulário. Retorna true quando todos os campos são válidos.

Limitações

  • As regras do lado do cliente são emitidas apenas para campos incluídos na validação do lado do servidor também. Sem Microsoft.Extensions.Validation, somente as propriedades de modelo de nível superior são validadas. A validação de objetos e coleções aninhados requer que o aplicativo chame AddValidation e que o modelo seja identificado. Para obter mais informações, consulte Validação no ASP.NET Core. Observe que essa limitação é um recurso intencional para ajudar a evitar bugs em que a validação do servidor autoritativo estaria ausente devido à configuração incorreta.
  • As entradas adicionadas a um formulário existente por uma atualização de renderização de streaming posterior não recebem validação do lado do cliente. Um formulário entregue em um único lote transmitido por streaming é processado normalmente.
  • Somente os atributos listados em atributos de validação com suporte têm implementações internas do lado do cliente. Por exemplo, um RangeAttribute com um tipo de operando não numérico só é aplicado no servidor. Outros atributos exigem uma regra de validação personalizada do lado do cliente.
  • Os validadores personalizados do JavaScript são síncronos. As regras que exigem uma chamada de rede ou outro trabalho assíncrono devem ser executadas no servidor ou usar a validação assíncrona com um modo de renderização interativo. Para obter mais informações, consulte ASP.NET Core Blazor validação de formulário avançada.

Recursos adicionais