la convalida dei form di ASP.NET Core Blazor

Nota

Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 10 di questo articolo.

Avviso

Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere .NET e .NET Core Support Policy. Per la versione corrente, vedere la versione .NET 10 di questo articolo.

Questo articolo illustra come convalidare l'input dell'utente nei Blazor moduli.

Per la maggior parte dei moduli, l'approccio più semplice e consigliato consiste nell'aggiungere attributi di convalida delle annotazioni dati al modello e inserire un DataAnnotationsValidator componente in EditForm. Blazor supporta anche la convalida personalizzata tramite il modulo EditContext, direttamente nel componente del modulo o in un componente validator riutilizzabile.

Gli articoli correlati forniscono altri dettagli:

Convalida con annotazioni dati

Il modello seguente usa 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; }
}

Aggiungere il modello a un EditFormoggetto , includere DataAnnotationsValidatore visualizzare gli errori con ValidationMessage<TValue> o ValidationSummary. Il OnValidSubmit callback viene richiamato solo quando la convalida ha esito positivo:

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

Per l'invio di un modulo SSR statico, assegnare un valore univoco a FormName e ricevere il modello inviato con [SupplyParameterFromForm]:

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

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

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

Per altre informazioni sull'invio di moduli e sull'associazione di modelli tra le modalità di rendering, vedere panoramica dei moduli ASP.NET Core Blazor e ASP.NET Core Blazorbinding dei moduli.

Senza un DataAnnotationsValidator componente, gli attributi di convalida nel modello non partecipano alla convalida del modulo.

Quando viene eseguita la convalida

Blazor esegue la convalida dei campi e dell’intero modulo:

  • La convalida dei campi viene eseguita dopo la modifica di un campo. In un modulo interattivo, questo si verifica in .NET mentre l'utente modifica il modulo.
  • La validazione dell'intero modulo viene normalmente eseguita quando EditForm gestisce l'invio tramite OnValidSubmit o OnInvalidSubmit. Un OnSubmit gestore assume il controllo della convalida, come descritto in Invio del modulo di controllo.

Un modulo SSR statico può fornire feedback in tempo reale nel browser con la convalida del modulo lato client di ASP.NET Core in SSR staticoBlazor. Il modulo viene convalidato di nuovo in modo autorevole nel server al momento della pubblicazione.

Un modulo SSR statico viene convalidato nel server quando pubblicato e non fornisce la convalida dei campi in tempo reale tra le richieste.

I risultati di convalida che identificano un membro sono associati a tale campo. I risultati senza un nome di membro sono associati al modello e vengono visualizzati in un riepilogo di convalida anziché nel componente di ValidationMessage un campo.

Configurare la convalida delle annotazioni dei dati

DataAnnotationsValidator abilita sempre la convalida di DataAnnotations per il modulo. Per usare le funzionalità di convalida estesa fornite dal Microsoft.Extensions.Validation pacchetto, chiamare il AddValidation metodo di estensione nel Program file:

builder.Services.AddValidation();

La AddValidation chiamata registra i servizi di convalida del pacchetto e attiva un generatore di origine che crea metadati di convalida per i tipi di modello individuati. Il comportamento disponibile dipende dal fatto che tali metadati includano il modello del modulo:

Configurazione Behavior
I metadati generati sono disponibili Convalida gli oggetti annidati e le raccolte e supporta la localizzazione dei messaggi.
I metadati generati non sono disponibili Convalida le proprietà di primo livello, ma non convalida oggetti o raccolte annidati e non usa la pipeline di localizzazione dei Microsoft.Extensions.Validation messaggi.
Configurazione Behavior
I metadati generati sono disponibili Convalida gli oggetti annidati e le raccolte.
I metadati generati non sono disponibili Convalida solo le proprietà di primo livello.

Le ValidatableTypeAttribute API e SkipValidationAttribute sono sperimentali in .NET 10. Per informazioni dettagliate e soluzioni alternative disponibili, vedere Convalida in ASP.NET Core.

Quando si usa Microsoft.Extensions.Validation, dichiarare i tipi di modello nei file C# (.cs) anziché Razor nei file di componente (.razor). Il generatore di origine crea metadati di convalida dall'origine C# e non può includere i tipi di modello dichiarati nei Razor componenti.

Per i requisiti di configurazione, l'ordine di convalida, le regole personalizzate, i grafici degli oggetti annidati e i metadati generati, vedere Convalida in ASP.NET Core.

Convalidare i grafici degli oggetti annidati

In .NET 9 o versioni precedenti DataAnnotationsValidator convalida le proprietà del modello di primo livello, ma non convalida in modo ricorsivo le proprietà della raccolta o del tipo complesso. Per la convalida ricorsiva, usare ObjectGraphDataAnnotationsValidator e [ValidateComplexType] dal pacchetto sperimentaleMicrosoft.AspNetCore.Components.DataAnnotations.Validation:

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

Il pacchetto rimane sperimentale in queste versioni del framework.

Attributo [CompareProperty]

Per .NET 5 o versioni precedenti, usare il pacchetto ComparePropertyAttribute sperimentale anziché CompareAttribute. ComparePropertyAttribute associa il risultato della convalida al campo in modo coerente durante la convalida del campo e del modulo completo.

Scrivere regole personalizzate basate su modello

Quando gli attributi predefiniti non possono esprimere una regola, usare un oggetto personalizzato ValidationAttribute o IValidatableObject. Per indicazioni dettagliate, vedere Convalida in ASP.NET Core.

Scrivere regole personalizzate basate su modello

Quando gli attributi predefiniti non possono esprimere una regola, usare un attributo di convalida personalizzato o implementare IValidatableObject. Entrambi passano attraverso DataAnnotationsValidator.

Quando si restituisce un ValidationResult da un attributo personalizzato, includere il nome del membro convalidato in modo che il risultato possa essere visualizzato nel componente ValidationMessage di quel campo.

Gli attributi personalizzati possono risolvere i servizi registrati tramite GetService.

Aggiungere la convalida tramite EditContext

EditForm crea automaticamente un oggetto EditContext quando viene assegnato il Model relativo parametro. Per usare direttamente le API di convalida, creare manualmente EditContext e assegnarla a EditContext. Non assegnare entrambi Model e EditContext allo stesso modulo.

La convalida personalizzata viene comunemente usata:

Il modello di modulo interattivo seguente aggiunge una regola business a livello di modulo insieme alla convalida delle annotazioni dei dati e controlla nuovamente la regola quando uno dei campi pertinenti cambia:

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

Un gestore OnFieldChanged riceve il campo modificato in e.FieldIdentifier. Cancellare o sostituire i messaggi interessati e chiamare NotifyValidationStateChanged, come illustrato nell'esempio precedente.

L'SSR statico non fornisce la convalida dei campi di .NET in tempo reale tra una richiesta e l'altra.

Per la validazione asincrona dell'intero modulo, chiamare e.AddAsyncValidator da una routine di gestione OnValidationRequested. Per la convalida asincrona dei campi di un modulo interattivo, richiamare EditContext.RegisterAsyncFieldValidator in un gestore OnFieldChanged. Una nuova convalida asincrona per lo stesso campo sostituisce e annulla quella precedente.

Per gli attributi di convalida asincrona basati su modello, vedere Convalida in ASP.NET Core. Per un componente di validator riutilizzabile completo, vedere ASP.NET Core convalida Blazor avanzata dei moduli.

Per un'implementazione riutilizzabile che incapsula le sottoscrizioni di eventi e il relativo archivio messaggi, vedere ASP.NET Core convalida Blazor avanzata dei moduli.

Visualizzare i messaggi di convalida

Usare ValidationMessage<TValue> per visualizzare i messaggi associati a un campo:

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

Usare ValidationSummary per visualizzare i messaggi per il modulo:

<ValidationSummary />

Assegnare il parametro Model del riepilogo per limitarlo ai messaggi associati a un determinato modello:

<ValidationSummary Model="Model" />

Per esaminare i messaggi correnti nel codice, chiamare GetValidationMessages:

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

Questi metodi leggono lo stato di convalida corrente. Non avviano la convalida.

Personalizzare l'aspetto della convalida

Blazor applica classi CSS che rappresentano lo stato del campo e del messaggio:

Elemento Classi
Input valid o invalid, più modified dopo che l'utente modifica il campo
Messaggio di convalida validation-message
Riepilogo della convalida validation-summary-errors oppure validation-summary-valid

Gli input con convalida asincrona dei campi usano pending o faulted, facoltativamente con modified, anziché valid o invalid mentre si applica lo stato corrispondente.

I modelli di Blazor progetto includono stili per le classi valide e non valide comuni. Aggiungere stili per altre classi in base alle esigenze. ValidationMessage e ValidationSummary accettano anche attributi HTML arbitrari. Se si specifica un class attributo, la classe predefinita del componente viene sostituita.

Per modificare le classi applicate ai componenti di input, derivare da 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";
    }
}

Un oggetto personalizzato FieldCssClassProvider determina il valore completo della classe per ogni campo. Se il form usa la convalida asincrona dei campi, gestisci IsValidationPending(fieldIdentifier) e IsValidationFaulted(fieldIdentifier) nel provider quando sono richieste classi in sospeso o in errore.

Assegnare il provider al modulo EditContext:

editContext.SetFieldCssClassProvider(
    new BootstrapFieldCssClassProvider());

Per il markup di input personalizzato, chiamare FieldCssClass per ottenere la classe selezionata dal provider corrente.

Rispondere allo stato di convalida

EditContext espone lo stato di convalida corrente senza avviare la convalida.

  • Utilizzare IsModified(field) o IsModified() per determinare se un campo o un campo nel modulo è stato modificato.
  • Utilizzare GetValidationMessages(field) o GetValidationMessages() per esaminare i messaggi di modulo o di campo corrente.

Utilizzare IsValid(field) per determinare se un campo dispone attualmente di messaggi di convalida.

Per un campo, è possibile controllare l'assenza di messaggi con !editContext.GetValidationMessages(field).Any().

L'esempio seguente visualizza l'interfaccia utente personalizzata solo dopo la modifica di un campo e non è valido:

@{
    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>
}

I componenti di input, ValidationMessagee ValidationSummary si aggiornano quando lo stato di convalida cambia. Un componente che visualizza altri elementi dell'interfaccia utente per la convalida condizionale deve registrarsi a OnValidationStateChanged e chiamare StateHasChanged:

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

Annullare la sottoscrizione a OnValidationStateChanged quando il componente viene eliminato.

Usare IsValidationPending(field) e IsValidationFaulted(field) per la convalida asincrona dei campi. I metodi senza parametri descrivono i passaggi a livello ValidateAsync di modulo e non aggregano lo stato di ogni campo.

Questi stati includono anche il lavoro asincrono eseguito da DataAnnotationsValidator. Un AsyncValidationAttribute applicato a una proprietà utilizza lo stato del campo durante la convalida, incluse le classi CSS predefinite pending e faulted. Durante ValidateAsync, gli attributi asincroni e IAsyncValidatableObject contribuiscono allo stato a livello di modulo segnalato dai metodi senza parametri.

Gli indicatori live in attesa richiedono una modalità di rendering interattiva. Durante un post di modulo SSR statico, la convalida lato server viene completata prima del rendering della risposta.

Invio del modulo di controllo

EditForm fornisce tre callback di invio:

Callback Behavior
OnValidSubmit Viene eseguito dopo l'esito positivo della convalida automatica.
OnInvalidSubmit Viene eseguito dopo l'esito negativo della convalida automatica.
OnSubmit Assegna al gestore il controllo della convalida e dell'invio.

OnValidSubmit e OnInvalidSubmit possono essere usati insieme. Non combinare OnSubmit con nessuno dei due.

EditForm usa ValidateAsync prima di invocare OnValidSubmit o OnInvalidSubmit, quindi attende i validatori sincroni e asincroni. Quando si gestisce OnSubmit, chiamare ValidateAsync prima di elaborare il modulo:

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

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

Il metodo sincrono Validate è obsoleto in .NET 11. Non attende il completamento della validazione asincrona e solleva un'eccezione se un gestore tenta di registrare operazioni asincrone.

Per i moduli interattivi, è possibile usare lo stato di attesa a livello di modulo per disabilitare l'invio mentre ValidateAsync è in esecuzione:

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

Quando si gestisce OnSubmit, chiamare Validate prima di elaborare il modulo:

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

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

Risorse aggiuntive