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

Este artigo explica como Blazor adiciona validação em tempo real do lado do cliente a formulários que utilizam renderização estática do lado do servidor (SSR estático). O navegador valida campos individuais à medida que o utilizador os edita e valida o formulário completo antes de ser submetido. Se a verificação do lado do cliente passar, o formulário é submetido e validado novamente no servidor.

Formulários que utilizam um modo de renderização interativo não utilizam a funcionalidade estática de validação SSR do lado do cliente descrita neste artigo. Tanto a validação por campo como a validação de envio do formulário completo são executadas em .NET através 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 aplica-as usando JavaScript antes de o formulário ser submetido. O utilizador vê erros de validação sem necessidade de fazer ida e volta ao servidor.

A validação do lado do cliente ativa-se automaticamente quando as seguintes condições são cumpridas:

Para o conjunto incorporado de atributos de validação, não é necessária configuração JavaScript, pacote adicional ou registo de serviço. A secção Regras personalizadas de validação do lado do cliente descreve como adicionar suporte para atributos de validação personalizados.

Importante

A validação do lado do cliente é uma melhoria da experiência do utilizador, não uma validação autoritativa. Pode ser contornado desativando ou modificando a execução em JavaScript do navegador. A validação do lado do servidor é executada após a publicação do formulário e mantém-se autoritativa. Nunca confie na validação do lado do cliente para proteger a integridade dos dados.

Atributos de validação suportados

Os seguintes System.ComponentModel.DataAnnotations atributos são aplicados do lado do cliente, correspondendo ao comportamento das 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 impostos no cliente por predefinição. Continuam a ser executados no servidor depois de o formulário ser submetido. Para fornecer uma regra do lado do cliente para um atributo personalizado, consulte a secção Regras de validação personalizadas do lado do cliente .

Temporização da validação

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

Depois de um campo mostrar um erro de validação ou depois de o formulário ter sido submetido pelo menos uma vez, o campo é validado novamente em cada tecla para que as correções sejam reflexas imediatamente.

Submeter o formulário valida todos os campos rastreados. Se algum campo for inválido, a submissão é bloqueada e o foco passa para o primeiro campo inválido.

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

A validação do lado do cliente serve ValidationMessage<TValue> para mostrar mensagens para campos individuais e ValidationSummary para mostrar mensagens para todo o formulário, da mesma forma que a validação interativa reporta mensagens aos utilizadores.

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

Os atributos ARIA nos campos de entrada e nos contentores de mensagens de validação são geridos automaticamente por Blazor, assim as tecnologias assistivas anunciam erros de validação sem configuração adicional.

Classes CSS do estado de validação

O motor de validação no cliente aplica as mesmas classes CSS que a validação interativa de Blazor, conforme apresentado na tabela seguinte.

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

A validação do lado do cliente também chama a API de Validação de Restrições do navegador, ou seja, as pseudo-classes :valid CSS padrão e :invalid refletem o estado atual de validação de cada entrada.

Optar por não participar na validação do lado do cliente

A funcionalidade pode ser desativada em vários níveis. A validação do lado do servidor não é afetada por nenhuma das opções desta secção.

Optar por não optar por um único formulário

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

<DataAnnotationsValidator DisableClientValidation="true" />

Optar por não participar na aplicação inteira

Defina DisableClientValidation em RazorComponentsServiceOptions quando os serviços de componentes Razor forem registados no ficheiro Program:

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

A opção global tem prioridade. Quando está definido para true, os formulários não emitem regras de validação do lado do cliente.

Opte por não ter um único botão de submissão

Use o atributo HTMLformnovalidate padrão no botão. O formulário é publicado sem verificação do lado do cliente, e a validação do lado do servidor continua a correr após a publicação:

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

Isto pode ser usado para implementar um botão de "guardar rascunho" ou "voltar" que não exija um formulário completamente válido para que a submissão tenha sucesso.

Regras personalizadas de validação do lado do cliente

Os atributos de validação personalizados continuam a correr no servidor, mas não têm uma implementação do lado do cliente por defeito. A aplicação de uma regra personalizada no navegador envolve dois passos: emitir a regra a partir do atributo .NET e registar um validador JavaScript correspondente. A implementação do lado do servidor mantém-se autoritativa.

Emitir a regra a partir do .NET

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

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

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

Aplicar o atributo ao modelo da forma habitual:

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

Registe o validador JavaScript

No JavaScript, chamar Blazor.formValidation.addValidator(name, validator) para associar um nome de regra a uma função validadora. Devem name corresponder ClientValidationRule.Nameexatamente , incluindo o revestimento. Os registos são para toda a aplicação, e registar novamente o mesmo nome substitui o validador anterior.

Warning

Se não houver um validador JavaScript registado para um nome de regra emitido, a regra é omitida no navegador. A validação do lado do servidor continua a correr quando o formulário é publicado.

Registe validadores personalizados uma vez a partir do código de arranque da aplicação. Escolha o local de registo com base em como Blazor começa, conforme descrito na tabela seguinte.

Blazor arranque Local de registo
Arranque automático (predefinido) Um script imediatamente após blazor.web.js
Manual Blazor.start() A continuação retornada por Blazor.start()
Um de dois estilos de arranque A função de callback de um inicializador JavaScript afterWebStarted

Um inicializador JavaScript funciona com qualquer um dos estilos de arranque. Num ficheiro nomeado {ASSEMBLY NAME}.lib.module.js na pasta da wwwroot aplicação:

// 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 o arranque automático, um script validador específico da aplicação 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.

No arranque manual, defina o registo num script de aplicação:

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 desativada e registe 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

Registe validadores a partir do código de arranque da aplicação, não de um componente de página ou formulário. Um script de componente pode ser executado antes de Blazor ser iniciado, e os scripts adicionados pela navegação melhorada não são executados. Os componentes SSR estáticos também não podem utilizar IJSRuntime porque não dispõem de um ambiente de execução .NET interativo.

Escrever funções de validação em JavaScript

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

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

Espera-se que o validador devolva { success: true } quando o valor for válido. Devolva { success: false } para usar a mensagem da regra fornecida pelo servidor, ou pode devolver { success: false, message: '...' } para substituir a mensagem para essa chamada.

Os valores vazios devem normalmente ser tratados como válidos por regras diferentes de required, permitindo que um campo opcional permaneça vazio, ao mesmo tempo que valida os valores introduzidos.

Implemente a mesma semântica de regras em .NET e JavaScript, incluindo sensibilidade a maiúsculas minúsculas, normalização e tratamento de valores vazios. Se as implementações diferirem, o navegador e a validação autoritativa do lado do servidor podem produzir resultados diferentes.

Validar formulário a pedido

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

Método Descrição
validateField(element) Valida um único elemento de campo e atualiza o seu ecrã de erro. Devolve true quando válido.
validateForm(form) Valida todos os campos rastreados num formulário. Retorna true quando todos os campos são válidos.

Limitations

  • As regras do lado do cliente são emitidas apenas para campos incluídos na validação do lado do servidor. Sem Microsoft.Extensions.Validation, apenas as propriedades do modelo de topo são validadas. A validação de objetos aninhados e coleções exige que a aplicação chame AddValidation e que o modelo seja detetado. Para mais informações, consulte Validação no ASP.NET Core. Note-se que esta limitação é uma funcionalidade intencional para ajudar a prevenir bugs em que a validação autoritativa do servidor estaria em falta devido a má configuração.
  • Entradas adicionadas a um formulário existente por uma atualização posterior de renderização em streaming não recebem validação do lado do cliente. Um formulário enviado num único lote em streaming é processado normalmente.
  • Apenas os atributos listados em Atributos de validação suportados têm implementações integradas do lado do cliente. Por exemplo, a RangeAttribute com um tipo de operando não numérico só é imposta no servidor. Outros atributos requerem uma regra de validação personalizada do lado do cliente.
  • Validadores JavaScript personalizados são síncronos. Regras que exigem uma chamada de rede ou outro trabalho assíncrono devem ser executadas no servidor ou usar validação assíncrona com um modo de renderização interativa. Para mais informações, consulte validação avançada de formulários ASP.NET CoreBlazor.

Recursos adicionais