ASP.NET Core Blazor validação de formulários

Observação

Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 10 deste artigo.

Advertência

Esta versão do ASP.NET Core já não é suportada. Para mais informações, consulte a Política de Suporte do .NET e .NET Core. Para a versão atual, consulte a versão .NET 10 deste artigo.

Este artigo explica como validar a entrada do utilizador em Blazor formulários.

Para a maioria dos formulários, a abordagem mais simples e recomendada é adicionar atributos de validação de anotações de dados ao modelo e colocar um DataAnnotationsValidator componente no EditForm. Blazor Também suporta validação personalizada através do formulário EditContext, seja diretamente no componente formulário ou num componente validador reutilizável.

Artigos relacionados fornecem mais detalhes:

Valide com anotações de dados

O seguinte modelo utiliza RequiredAttribute e RangeAttribute:

Starship.cs:

using System.ComponentModel.DataAnnotations;

public class Starship
{
    [Required]
    public string? Identifier { get; set; }

    [Range(1, 10, ErrorMessage = "Accommodation must be between 1 and 10.")]
    public int MaximumAccommodation { get; set; }
}

Adicione o modelo a um EditForm, inclua DataAnnotationsValidator, e exiba erros com ValidationMessage<TValue> ou ValidationSummary. O OnValidSubmit callback é invocado apenas quando a validação tem sucesso:

<EditForm Model="Model" OnValidSubmit="Submit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <p>
        <label>
            Identifier:
            <InputText @bind-Value="Model.Identifier" />
        </label>
        <ValidationMessage For="() => Model.Identifier" />
    </p>

    <p>
        <label>
            Maximum accommodation:
            <InputNumber @bind-Value="Model.MaximumAccommodation" />
        </label>
        <ValidationMessage For="() => Model.MaximumAccommodation" />
    </p>

    <button type="submit">Submit</button>
</EditForm>

@code {
    private Starship Model { get; } = new Starship();

    private void Submit()
    {
        // Process the valid form.
    }
}

Para uma submissão de formulário SSR estático, atribua um FormName exclusivo e receba o modelo submetido com [SupplyParameterFromForm]:

<EditForm Model="Model" FormName="starship" OnValidSubmit="Submit">
    ...
</EditForm>

@code {
    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();
}

Para mais informações sobre submissão de formulários e ligação de modelos entre modos de render, consulte a visão geral dos formulários ASP.NET Core Blazor e a ligação de formulários ASP.NET CoreBlazor.

Sem um DataAnnotationsValidator componente, os atributos de validação no modelo não participam na validação do formulário.

Quando a validação é executada

Blazor efetua a validação de campos e a validação de todo o formulário:

  • A validação de campo é executada após uma alteração de campo. Numa forma interativa, isto ocorre em .NET enquanto o utilizador edita o formulário.
  • A validação completa do formulário ocorre normalmente quando EditForm processa a submissão através de OnValidSubmit ou OnInvalidSubmit. Um OnSubmit processador assume o controlo sobre a validação, conforme descrito em Controlar o envio do formulário.

Um formulário SSR estático pode fornecer feedback em tempo real ao navegador com validação do formulário do lado do cliente ASP.NET Core Blazor em SSR estático. O formulário é novamente validado de forma autoritária no servidor quando publicado.

Um formulário SSR estático é validado no servidor quando publicado e não fornece validação em tempo real entre pedidos.

Resultados de validação que identificam um membro estão associados a esse campo. Os resultados sem nome do membro são associados ao modelo e aparecem num resumo de validação, em vez de no componente ValidationMessage de um campo.

Configurar validação de anotações de dados

DataAnnotationsValidator ativa sempre a validação com DataAnnotations para o formulário. Para utilizar as capacidades de validação estendida fornecidas pelo Microsoft.Extensions.Validation pacote, chame o AddValidation método de extensão no Program ficheiro:

builder.Services.AddValidation();

A AddValidation chamada regista os serviços de validação do pacote e ativa um gerador de origem que cria metadados de validação para os tipos de modelos descobertos. O comportamento disponível depende de esses metadados incluírem o modelo do formulário:

Configuração Behavior
Os metadados gerados estão disponíveis Valida objetos aninhados e coleções e suporta localização de mensagens.
Os metadados gerados não estão disponíveis Valida propriedades de topo, mas não valida objetos aninhados ou coleções e não utiliza o Microsoft.Extensions.Validation pipeline de localização de mensagens.
Configuração Behavior
Os metadados gerados estão disponíveis Valida objetos e coleções aninhadas.
Os metadados gerados não estão disponíveis Valida apenas propriedades de nível superior.

As ValidatableTypeAttribute APIs e SkipValidationAttribute são experimentais no .NET 10. Para detalhes e soluções alternativas, consulte Validação no ASP.NET Core.

Ao usar Microsoft.Extensions.Validation, declare tipos de modelo em ficheiros C# (.cs) em vez de Razor ficheiros componentes (.razor). O gerador de código-fonte cria metadados de validação a partir da fonte C# e não pode incluir tipos de modelos declarados nos Razor componentes.

Para requisitos de configuração, ordem de validação, regras personalizadas, grafos de objetos aninhados e metadados gerados, consulte Validação no ASP.NET Core.

Validar grafos de objetos aninhados

No .NET 9 ou anterior, DataAnnotationsValidator valida propriedades de modelo de topo mas não valida recursivamente propriedades de coleção ou de tipo complexo. Para validação recursiva, use ObjectGraphDataAnnotationsValidator e [ValidateComplexType] do pacote experimentalMicrosoft.AspNetCore.Components.DataAnnotations.Validation:

<EditForm Model="Model" OnValidSubmit="Submit">
    <ObjectGraphDataAnnotationsValidator />
    ...
</EditForm>
public class Starship
{
    [ValidateComplexType]
    public ShipDescription Description { get; set; } =
        new ShipDescription();
}

O pacote mantém-se experimental nestas versões de framework.

[CompareProperty] atributo

Para .NET 5 ou anterior, utilize o ComparePropertyAttribute do pacote experimental em vez de CompareAttribute. ComparePropertyAttribute associa o resultado da validação ao campo de forma consistente durante a validação em campo e em forma completa.

Escrever regras personalizadas baseadas em modelos

Quando os atributos incorporados não conseguem expressar uma regra, use um ValidationAttribute ou IValidatableObject personalizado. Para orientações detalhadas, consulte Validação no ASP.NET Core.

Escrever regras personalizadas baseadas em modelos

Quando os atributos incorporados não conseguem expressar uma regra, use um atributo de validação personalizado ou implemente IValidatableObject. Ambos os funcionam através de DataAnnotationsValidator.

Ao devolver ValidationResult de um atributo personalizado, inclua o nome do membro validado para que o resultado possa aparecer no componente ValidationMessage desse campo.

Atributos personalizados podem resolver serviços registados através de GetService.

Adicionar validação através EditContext

EditForm cria um EditContext automaticamente quando o seu Model parâmetro é atribuído. Para usar diretamente as APIs de validação, crie você mesmo o contexto e atribua-o ao parâmetro EditContext de EditForm. Não atribuas Model e EditContext ao mesmo formulário.

A validação personalizada utiliza comumente:

O seguinte padrão interativo de formulário adiciona uma regra de negócio ao nível do formulário juntamente com a validação de anotações de dados e verifica novamente a regra quando algum dos campos relevantes muda:

@implements IDisposable

<EditForm EditContext="editContext" OnValidSubmit="Submit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    ...
</EditForm>

@code {
    private Starship Model { get; } = new Starship();
    private EditContext editContext = default!;
    private ValidationMessageStore messages = default!;

    protected override void OnInitialized()
    {
        editContext = new EditContext(Model);
        messages = new ValidationMessageStore(editContext);
        editContext.OnValidationRequested += ValidateBusinessRules;
        editContext.OnFieldChanged += ValidateChangedField;
    }

    private void ValidateBusinessRules(
        object? sender, ValidationRequestedEventArgs e)
    {
        messages.Clear();
        ValidateIdentifier();
        editContext.NotifyValidationStateChanged();
    }

    private void ValidateChangedField(
        object? sender, FieldChangedEventArgs e)
    {
        if (e.FieldIdentifier.FieldName != nameof(Starship.Identifier) &&
            e.FieldIdentifier.FieldName != nameof(Starship.MaximumAccommodation))
        {
            return;
        }

        messages.Clear(
            editContext.Field(nameof(Starship.Identifier)));
        ValidateIdentifier();
        editContext.NotifyValidationStateChanged();
    }

    private void ValidateIdentifier()
    {
        if (Model.MaximumAccommodation == 1 &&
            string.IsNullOrWhiteSpace(Model.Identifier))
        {
            messages.Add(
                editContext.Field(nameof(Starship.Identifier)),
                "An identifier is required for a single-occupant ship.");
        }
    }

    private void Submit()
    {
        // Process the valid form.
    }

    public void Dispose()
    {
        editContext.OnValidationRequested -= ValidateBusinessRules;
        editContext.OnFieldChanged -= ValidateChangedField;
    }
}

Um OnFieldChanged manipulador recebe o campo alterado em e.FieldIdentifier. Limpe ou substitua as mensagens afetadas e ligue NotifyValidationStateChanged, como demonstra o exemplo anterior.

O SSR estático não fornece validação de campo .NET em tempo real entre pedidos.

Para a validação assíncrona do formulário completo, chame e.AddAsyncValidator num processador OnValidationRequested. Para validação de campo assíncrona numa forma interativa, chame EditContext.RegisterAsyncFieldValidator a partir de um OnFieldChanged handler. Uma nova validação assíncrona para o mesmo campo substitui e cancela a anterior.

Para atributos de validação assíncrona baseados em modelos, veja Validação no ASP.NET Core. Para um componente validador reutilizável completo, consulte validação avançada de formulários ASP.NET CoreBlazor.

Para uma implementação reutilizável que encapsula subscrições de eventos e o seu armazenamento de mensagens, consulte validação avançada de formulários ASP.NET CoreBlazor.

Mostrar mensagens de validação

Use ValidationMessage<TValue> para mostrar mensagens associadas a um campo:

<ValidationMessage For="() => Model.Identifier" />

A For expressão identifica o campo pela sua instância e propriedade do modelo. Blazor representa esta identidade com um FieldIdentifier, pelo que propriedades com o mesmo nome em diferentes instâncias de modelo são tratadas como campos diferentes. Usar uma expressão em vez de uma string também permite que ferramentas de refatoração atualizem a referência da propriedade.

Usar ValidationSummary para mostrar mensagens para o formulário:

<ValidationSummary />

Atribuir o parâmetro do Model resumo para o restringir a mensagens associadas a um modelo particular:

<ValidationSummary Model="Model" />

Para inspecionar as mensagens atuais no código, chame GetValidationMessages:

var allMessages = editContext.GetValidationMessages();
var fieldMessages = editContext.GetValidationMessages(
    editContext.Field(nameof(Starship.Identifier)));

Estes métodos leem o estado atual de validação. Eles não iniciam validação.

Personalizar a aparência da validação

Blazor aplica classes CSS que representam o estado do campo e da mensagem:

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

Entradas com validação de campo assíncrona usam pending ou faulted, opcionalmente com modified, em vez de valid ou invalid enquanto se aplica o estado correspondente.

Os Blazor modelos de projeto incluem estilos para as classes comuns válidas e inválidas. Adiciona estilos para outras classes conforme necessário. ValidationMessage e ValidationSummary também aceitam atributos HTML arbitrários. Fornecer um class atributo substitui a classe padrão do componente.

Para alterar as classes aplicadas aos componentes de entrada, herde de FieldCssClassProvider.

using Microsoft.AspNetCore.Components.Forms;

public sealed class BootstrapFieldCssClassProvider : FieldCssClassProvider
{
    public override string GetFieldCssClass(
        EditContext editContext,
        in FieldIdentifier fieldIdentifier)
    {
        if (!editContext.IsModified(fieldIdentifier))
        {
            return string.Empty;
        }

        return editContext.IsValid(fieldIdentifier)
            ? "is-valid"
            : "is-invalid";
    }
}
using System.Linq;
using Microsoft.AspNetCore.Components.Forms;

public sealed class BootstrapFieldCssClassProvider : FieldCssClassProvider
{
    public override string GetFieldCssClass(
        EditContext editContext,
        in FieldIdentifier fieldIdentifier)
    {
        if (!editContext.IsModified(fieldIdentifier))
        {
            return string.Empty;
        }

        return editContext.GetValidationMessages(fieldIdentifier).Any()
            ? "is-invalid"
            : "is-valid";
    }
}

Um personalizado FieldCssClassProvider determina o valor completo da classe para cada campo. Se o formulário usar validação assíncrona de campos, trate IsValidationPending(fieldIdentifier) e IsValidationFaulted(fieldIdentifier) no fornecedor quando forem necessárias classes pendente ou de falha.

Atribuir o prestador ao EditContext do formulário:

editContext.SetFieldCssClassProvider(
    new BootstrapFieldCssClassProvider());

Para marcação personalizada de entrada, ligue FieldCssClass para obter a classe selecionada pelo fornecedor atual.

Quando é atribuído um modelo a EditForm, o seu conteúdo subordinado recebe o EditContext gerado. Capturar o contexto através do Context parâmetro e chamar FieldCssClass para aplicar as classes do campo à marcação circundante:

<EditForm Model="Model" Context="editContext">
    <DataAnnotationsValidator />

    <div class="@editContext.FieldCssClass(
        () => Model.Identifier)">
        <InputText @bind-Value="Model.Identifier" />
        <ValidationMessage For="() => Model.Identifier" />
    </div>
</EditForm>

Responder ao estado de validação

EditContext expõe o estado atual de validação sem iniciar a validação.

  • Use IsModified(field) ou IsModified() para determinar se um campo ou qualquer campo do formulário mudou.
  • Utilizar GetValidationMessages(field) ou GetValidationMessages() para inspecionar as mensagens do campo ou do formulário atuais.

Use IsValid(field) para determinar se um campo tem atualmente mensagens de validação.

Para um campo, a ausência de mensagens pode ser verificada com !editContext.GetValidationMessages(field).Any().

O exemplo seguinte mostra uma interface personalizada apenas depois de um campo ser modificado e inválido:

@{
    var identifier = editContext.Field(nameof(Starship.Identifier));
}

@if (editContext.IsModified(identifier) &&
    !editContext.IsValid(identifier))
{
    <p>Correct the identifier before continuing.</p>
}
@{
    var identifier = editContext.Field(nameof(Starship.Identifier));
}

@if (editContext.IsModified(identifier) &&
    editContext.GetValidationMessages(identifier).Any())
{
    <p>Correct the identifier before continuing.</p>
}

Componentes de entrada, ValidationMessage, e ValidationSummary atualizam-se quando o estado de validação muda. Um componente que apresente outra interface de utilizador de validação condicional deve subscrever a OnValidationStateChanged e chamar StateHasChanged:

private void HandleValidationStateChanged(
    object? sender, ValidationStateChangedEventArgs e) =>
    _ = InvokeAsync(StateHasChanged);

Cancelar a subscrição de OnValidationStateChanged aquando da eliminação do componente.

Utilize IsValidationPending(field) e IsValidationFaulted(field) para validação assíncrona de campos. Os métodos sem parâmetros descrevem validações ao nível do formulário ValidateAsync e não consolidam o estado de todos os campos.

Estes estados incluem também trabalho assíncrono realizado por DataAnnotationsValidator. Um AsyncValidationAttribute aplicado a uma propriedade usa o estado do campo durante a validação do campo, incluindo as classes padrão pending e faulted CSS. Durante ValidateAsync, atributos assíncronos e IAsyncValidatableObject contribuem para o estado ao nível da forma reportado pelos métodos sem parâmetros.

Os indicadores de pendência em tempo real requerem um modo de renderização interativo. Durante a publicação estática de um formulário SSR, a validação do lado do servidor é concluída antes de a resposta ser renderizada.

Submissão do formulário de controlo

EditForm fornece três callbacks de submissão:

Chamada de Retorno Behavior
OnValidSubmit É executado após a validação automática ser concluída com êxito.
OnInvalidSubmit Executa após falhar a validação automática.
OnSubmit Dá ao handler controlo sobre a validação e submissão.

OnValidSubmit e OnInvalidSubmit podem ser usados em conjunto. Não combine OnSubmit com qualquer um deles.

EditForm usa ValidateAsync antes de invocar OnValidSubmit ou OnInvalidSubmit, por isso aguarda validadores síncronos e assíncronos. Ao tratar OnSubmit, chame ValidateAsync antes de processar o formulário:

<EditForm EditContext="editContext" OnSubmit="HandleSubmit">
    ...
</EditForm>

@code {
    private async Task HandleSubmit(EditContext editContext)
    {
        if (await editContext.ValidateAsync())
        {
            await SaveAsync();
        }
    }
}

O método síncrono Validate está obsoleto no .NET 11. Não aguarda a validação assíncrona e gera um erro se um processador tentar registar uma operação assíncrona.

Para formulários interativos, o estado pendente do formulário pode ser usado para desativar o envio enquanto ValidateAsync está em execução:

<button type="submit" disabled="@editContext.IsValidationPending()">
    Save
</button>

Ao tratar OnSubmit, chame Validate antes de processar o formulário:

<EditForm EditContext="editContext" OnSubmit="HandleSubmit">
    ...
</EditForm>

@code {
    private void HandleSubmit(EditContext editContext)
    {
        if (editContext.Validate())
        {
            Save();
        }
    }
}

Recursos adicionais