Sdílet prostřednictvím


ověřování základních Blazor formulářů ASP.NET

Poznámka:

Toto není nejnovější verze tohoto článku. Aktuální verzi najdete ve verzi .NET 8 tohoto článku.

Upozorňující

Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v tématu .NET a .NET Core Zásady podpory. Aktuální verzi najdete ve verzi .NET 8 tohoto článku.

Důležité

Tyto informace se týkají předběžného vydání produktu, který může být podstatně změněn před komerčním vydáním. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.

Aktuální verzi najdete ve verzi .NET 8 tohoto článku.

Tento článek vysvětluje, jak používat ověřování ve Blazor formulářích.

Ověření formuláře

Ve scénářích základního EditForm ověřování formulářů může instance k ověření polí formuláře použít deklarované EditContext instance a ValidationMessageStore instance. Obslužná rutina pro OnValidationRequested událost EditContext spuštění vlastní logiky ověřování. Výsledek obslužné rutiny aktualizuje ValidationMessageStore instanci.

Základní ověření formuláře je užitečné v případech, kdy je model formuláře definován v rámci komponenty hostující formulář, a to buď jako členy přímo na komponentě, nebo v podtřídě. Použití komponenty validátoru se doporučuje, když se používá nezávislá třída modelu napříč několika komponentami.

Ověření Blazor Web Appna straně klienta vyžaduje aktivní BlazorSignalR okruh. Ověřování na straně klienta není k dispozici pro formuláře v součástech, které přijaly statické vykreslování na straně serveru (statické SSR). Formuláře, které přijímají statické služby SSR, se po odeslání formuláře ověřují na serveru.

V následující komponentě HandleValidationRequested metoda obslužné rutiny vymaže všechny existující ověřovací zprávy voláním ValidationMessageStore.Clear před ověřením formuláře.

Starship8.razor:

@page "/starship-8"
@implements IDisposable
@inject ILogger<Starship8> Logger

<h2>Holodeck Configuration</h2>

<EditForm EditContext="editContext" OnValidSubmit="Submit" FormName="Starship8">
    <div>
        <label>
            <InputCheckbox @bind-Value="Model!.Subsystem1" />
            Safety Subsystem
        </label>
    </div>
    <div>
        <label>
            <InputCheckbox @bind-Value="Model!.Subsystem2" />
            Emergency Shutdown Subsystem
        </label>
    </div>
    <div>
        <ValidationMessage For="() => Model!.Options" />
    </div>
    <div>
        <button type="submit">Update</button>
    </div>
</EditForm>

@code {
    private EditContext? editContext;

    [SupplyParameterFromForm]
    private Holodeck? Model { get; set; }

    private ValidationMessageStore? messageStore;

    protected override void OnInitialized()
    {
        Model ??= new();
        editContext = new(Model);
        editContext.OnValidationRequested += HandleValidationRequested;
        messageStore = new(editContext);
    }

    private void HandleValidationRequested(object? sender,
        ValidationRequestedEventArgs args)
    {
        messageStore?.Clear();

        // Custom validation logic
        if (!Model!.Options)
        {
            messageStore?.Add(() => Model.Options, "Select at least one.");
        }
    }

    private void Submit() => Logger.LogInformation("Submit: Processing form");

    public class Holodeck
    {
        public bool Subsystem1 { get; set; }
        public bool Subsystem2 { get; set; }
        public bool Options => Subsystem1 || Subsystem2;
    }

    public void Dispose()
    {
        if (editContext is not null)
        {
            editContext.OnValidationRequested -= HandleValidationRequested;
        }
    }
}
@page "/starship-8"
@implements IDisposable
@inject ILogger<Starship8> Logger

<h2>Holodeck Configuration</h2>

<EditForm EditContext="editContext" OnValidSubmit="Submit" FormName="Starship8">
    <div>
        <label>
            <InputCheckbox @bind-Value="Model!.Subsystem1" />
            Safety Subsystem
        </label>
    </div>
    <div>
        <label>
            <InputCheckbox @bind-Value="Model!.Subsystem2" />
            Emergency Shutdown Subsystem
        </label>
    </div>
    <div>
        <ValidationMessage For="() => Model!.Options" />
    </div>
    <div>
        <button type="submit">Update</button>
    </div>
</EditForm>

@code {
    private EditContext? editContext;

    [SupplyParameterFromForm]
    private Holodeck? Model { get; set; }

    private ValidationMessageStore? messageStore;

    protected override void OnInitialized()
    {
        Model ??= new();
        editContext = new(Model);
        editContext.OnValidationRequested += HandleValidationRequested;
        messageStore = new(editContext);
    }

    private void HandleValidationRequested(object? sender,
        ValidationRequestedEventArgs args)
    {
        messageStore?.Clear();

        // Custom validation logic
        if (!Model!.Options)
        {
            messageStore?.Add(() => Model.Options, "Select at least one.");
        }
    }

    private void Submit() => Logger.LogInformation("Submit: Processing form");

    public class Holodeck
    {
        public bool Subsystem1 { get; set; }
        public bool Subsystem2 { get; set; }
        public bool Options => Subsystem1 || Subsystem2;
    }

    public void Dispose()
    {
        if (editContext is not null)
        {
            editContext.OnValidationRequested -= HandleValidationRequested;
        }
    }
}
@page "/starship-8"
@implements IDisposable
@inject ILogger<Starship8> Logger

<h2>Holodeck Configuration</h2>

<EditForm EditContext="editContext" OnValidSubmit="Submit">
    <div>
        <label>
            <InputCheckbox @bind-Value="Model!.Subsystem1" />
            Safety Subsystem
        </label>
    </div>
    <div>
        <label>
            <InputCheckbox @bind-Value="Model!.Subsystem2" />
            Emergency Shutdown Subsystem
        </label>
    </div>
    <div>
        <ValidationMessage For="() => Model!.Options" />
    </div>
    <div>
        <button type="submit">Update</button>
    </div>
</EditForm>

@code {
    private EditContext? editContext;

    public Holodeck? Model { get; set; }

    private ValidationMessageStore? messageStore;

    protected override void OnInitialized()
    {
        Model ??= new();
        editContext = new(Model);
        editContext.OnValidationRequested += HandleValidationRequested;
        messageStore = new(editContext);
    }

    private void HandleValidationRequested(object? sender,
        ValidationRequestedEventArgs args)
    {
        messageStore?.Clear();

        // Custom validation logic
        if (!Model!.Options)
        {
            messageStore?.Add(() => Model.Options, "Select at least one.");
        }
    }

    private void Submit()
    {
        Logger.LogInformation("Submit called: Processing the form");
    }

    public class Holodeck
    {
        public bool Subsystem1 { get; set; }
        public bool Subsystem2 { get; set; }
        public bool Options => Subsystem1 || Subsystem2;
    }

    public void Dispose()
    {
        if (editContext is not null)
        {
            editContext.OnValidationRequested -= HandleValidationRequested;
        }
    }
}

Komponenta validátoru datových poznámek a vlastní ověření

Komponenta DataAnnotationsValidator připojí ověření datových poznámek k kaskádové EditContextsadě . Povolení ověření datových poznámek vyžaduje komponentu DataAnnotationsValidator . Pokud chcete použít jiný systém ověřování než datové poznámky, použijte místo komponenty vlastní implementaci DataAnnotationsValidator . Implementace architektury pro DataAnnotationsValidator jsou k dispozici pro kontrolu v referenčním zdroji:

Poznámka:

Odkazy na dokumentaci k referenčnímu zdroji .NET obvykle načítají výchozí větev úložiště, která představuje aktuální vývoj pro příští verzi .NET. Pokud chcete vybrat značku pro konkrétní verzi, použijte rozevírací seznam pro přepnutí větví nebo značek. Další informace najdete v tématu Jak vybrat značku verze zdrojového kódu ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Blazor provádí dva typy ověřování:

  • Ověření pole se provádí, když uživatel zarážky mimo pole. Během ověřování pole komponenta DataAnnotationsValidator přidruží všechny ohlášené výsledky ověření k poli.
  • Ověření modelu se provede, když uživatel odešle formulář. Během ověřování DataAnnotationsValidator modelu se komponenta pokusí určit pole na základě názvu člena, který hlásí výsledky ověření. Výsledky ověření, které nejsou přidružené k jednotlivým členům, jsou přidružené k modelu, nikoli k poli.

Komponenty validátoru

Komponenty validátoru podporují ověřování formuláře správou ValidationMessageStore formuláře .EditContext

Architektura Blazor poskytuje komponentu DataAnnotationsValidator pro připojení podpory ověřování k formulářům na základě ověřovacích atributů (datových poznámek). Můžete vytvořit vlastní komponenty validátoru pro zpracování ověřovacích zpráv pro různé formuláře na stejné stránce nebo ve stejném formuláři v různých krocích zpracování formulářů (například ověření klienta následované ověřením serveru). Příklad komponenty validátoru uvedený v této části , CustomValidationse používá v následujících částech tohoto článku:

Z předdefinovaných validátorů datových poznámek není podporován Blazorpouze [Remote] ověřovací atribut .

Poznámka:

Vlastní atributy ověření datových poznámek lze v mnoha případech použít místo vlastních komponent validátoru. Vlastní atributy použité u modelu formuláře se aktivují pomocí DataAnnotationsValidator komponenty. Při použití s ověřením serveru musí být všechny vlastní atributy použité na modelu spustitelné na serveru. Další informace najdete v části Vlastní ověřovací atributy .

Vytvoření komponenty validátoru z ComponentBase:

  • EditContext Formulář je kaskádový parametr komponenty.
  • Při inicializaci komponenty validátoru se vytvoří nový ValidationMessageStore , aby se zachoval aktuální seznam chyb formuláře.
  • Úložiště zpráv obdrží chyby, když vývojář kód v komponentě formuláře volá metodu DisplayErrors . Chyby jsou předány DisplayErrors metodě v .Dictionary<string, List<string>> Ve slovníku je klíčem název pole formuláře, které obsahuje jednu nebo více chyb. Hodnota je seznam chyb.
  • Zprávy jsou vymazány, pokud došlo k některé z následujících:
    • Při vyvolání události se vyžaduje EditContext OnValidationRequested ověření. Všechny chyby jsou vymazány.
    • Pole se změní ve formuláři při vyvolání OnFieldChanged události. Vymažou se pouze chyby pole.
    • Metoda ClearErrors je volána kódem vývojáře. Všechny chyby jsou vymazány.

Aktualizujte obor názvů v následující třídě tak, aby odpovídal oboru názvů vaší aplikace.

CustomValidation.cs:

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;

namespace BlazorSample;

public class CustomValidation : ComponentBase
{
    private ValidationMessageStore? messageStore;

    [CascadingParameter]
    private EditContext? CurrentEditContext { get; set; }

    protected override void OnInitialized()
    {
        if (CurrentEditContext is null)
        {
            throw new InvalidOperationException(
                $"{nameof(CustomValidation)} requires a cascading " +
                $"parameter of type {nameof(EditContext)}. " +
                $"For example, you can use {nameof(CustomValidation)} " +
                $"inside an {nameof(EditForm)}.");
        }

        messageStore = new(CurrentEditContext);

        CurrentEditContext.OnValidationRequested += (s, e) => 
            messageStore?.Clear();
        CurrentEditContext.OnFieldChanged += (s, e) => 
            messageStore?.Clear(e.FieldIdentifier);
    }

    public void DisplayErrors(Dictionary<string, List<string>> errors)
    {
        if (CurrentEditContext is not null)
        {
            foreach (var err in errors)
            {
                messageStore?.Add(CurrentEditContext.Field(err.Key), err.Value);
            }

            CurrentEditContext.NotifyValidationStateChanged();
        }
    }

    public void ClearErrors()
    {
        messageStore?.Clear();
        CurrentEditContext?.NotifyValidationStateChanged();
    }
}

Důležité

Určení oboru názvů je vyžadováno při odvození z ComponentBase. Zadání oboru názvů způsobí chybu sestavení:

Tag helpers cannot target tag name '<global namespace>.{CLASS NAME}' because it contains a ' ' character.

Zástupný {CLASS NAME} symbol je název třídy komponenty. Příklad vlastního validátoru v této části určuje ukázkový obor názvů BlazorSample.

Poznámka:

Anonymní výrazy lambda jsou registrované obslužné rutiny událostí pro OnValidationRequested a OnFieldChanged v předchozím příkladu. V tomto scénáři není nutné implementovat IDisposable a odhlásit delegáty událostí. Další informace najdete v tématu Životní cyklus komponent ASP.NET Core Razor.

Ověřování obchodní logiky pomocí komponenty validátoru

Pro obecné ověření obchodní logiky použijte komponentu validátoru, která přijímá chyby formuláře ve slovníku.

Základní ověřování je užitečné v případech, kdy je model formuláře definován v rámci komponenty hostující formulář, a to buď jako členy přímo na komponentě, nebo v podtřídě. Použití komponenty validátoru se doporučuje, když se používá nezávislá třída modelu napříč několika komponentami.

V následujícím příkladu:

  • Zkrácená verze Starfleet Starship Database formuláře (Starship3komponenty) části Příklad formuláře článku Vstupní komponenty, která přijímá pouze klasifikaci a popis hvězdicové lodi. Ověření datových poznámek se při odesílání formuláře neaktivuje, protože DataAnnotationsValidator součást není součástí formuláře.
  • Používá se komponenta CustomValidation z části Součásti validátoru tohoto článku.
  • Ověření vyžaduje hodnotu pro popis lodi (Description), pokud uživatel vybereDefense klasifikaci expedice (Classification).

Když jsou v komponentě nastavené ověřovací zprávy, přidají se do validátoru ValidationMessageStore a zobrazí se v souhrnu EditFormověření.

Starship9.razor:

@page "/starship-9"
@inject ILogger<Starship9> Logger

<h1>Starfleet Starship Database</h1>

<h2>New Ship Entry Form</h2>

<EditForm Model="Model" OnValidSubmit="Submit" FormName="Starship9">
    <CustomValidation @ref="customValidation" />
    <ValidationSummary />
    <div>
        <label>
            Primary Classification:
            <InputSelect @bind-Value="Model!.Classification">
                <option value="">
                    Select classification ...
                </option>
                <option checked="@(Model!.Classification == "Exploration")" 
                    value="Exploration">
                    Exploration
                </option>
                <option checked="@(Model!.Classification == "Diplomacy")" 
                    value="Diplomacy">
                    Diplomacy
                </option>
                <option checked="@(Model!.Classification == "Defense")" 
                    value="Defense">
                    Defense
                </option>
            </InputSelect>
        </label>
    </div>
    <div>
        <label>
            Description (optional):
            <InputTextArea @bind-Value="Model!.Description" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    private CustomValidation? customValidation;

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

    protected override void OnInitialized() =>
        Model ??= new() { ProductionDate = DateTime.UtcNow };

    private void Submit()
    {
        customValidation?.ClearErrors();

        var errors = new Dictionary<string, List<string>>();

        if (Model!.Classification == "Defense" &&
                string.IsNullOrEmpty(Model.Description))
        {
            errors.Add(nameof(Model.Description),
                new() { "For a 'Defense' ship classification, " +
                "'Description' is required." });
        }

        if (errors.Any())
        {
            customValidation?.DisplayErrors(errors);
        }
        else
        {
            Logger.LogInformation("Submit called: Processing the form");
        }
    }
}
@page "/starship-9"
@inject ILogger<Starship9> Logger

<h1>Starfleet Starship Database</h1>

<h2>New Ship Entry Form</h2>

<EditForm Model="Model" OnValidSubmit="Submit" FormName="Starship9">
    <CustomValidation @ref="customValidation" />
    <ValidationSummary />
    <div>
        <label>
            Primary Classification:
            <InputSelect @bind-Value="Model!.Classification">
                <option value="">
                    Select classification ...
                </option>
                <option checked="@(Model!.Classification == "Exploration")" 
                    value="Exploration">
                    Exploration
                </option>
                <option checked="@(Model!.Classification == "Diplomacy")" 
                    value="Diplomacy">
                    Diplomacy
                </option>
                <option checked="@(Model!.Classification == "Defense")" 
                    value="Defense">
                    Defense
                </option>
            </InputSelect>
        </label>
    </div>
    <div>
        <label>
            Description (optional):
            <InputTextArea @bind-Value="Model!.Description" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    private CustomValidation? customValidation;

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

    protected override void OnInitialized() =>
        Model ??= new() { ProductionDate = DateTime.UtcNow };

    private void Submit()
    {
        customValidation?.ClearErrors();

        var errors = new Dictionary<string, List<string>>();

        if (Model!.Classification == "Defense" &&
                string.IsNullOrEmpty(Model.Description))
        {
            errors.Add(nameof(Model.Description),
                new() { "For a 'Defense' ship classification, " +
                "'Description' is required." });
        }

        if (errors.Any())
        {
            customValidation?.DisplayErrors(errors);
        }
        else
        {
            Logger.LogInformation("Submit called: Processing the form");
        }
    }
}
@page "/starship-9"
@inject ILogger<Starship9> Logger

<h1>Starfleet Starship Database</h1>

<h2>New Ship Entry Form</h2>

<EditForm Model="Model" OnValidSubmit="Submit">
    <CustomValidation @ref="customValidation" />
    <ValidationSummary />
    <div>
        <label>
            Primary Classification:
            <InputSelect @bind-Value="Model!.Classification">
                <option value="">Select classification ...</option>
                <option value="Exploration">Exploration</option>
                <option value="Diplomacy">Diplomacy</option>
                <option value="Defense">Defense</option>
            </InputSelect>
        </label>
    </div>
    <div>
        <label>
            Description (optional):
            <InputTextArea @bind-Value="Model!.Description" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    private CustomValidation? customValidation;

    public Starship? Model { get; set; }

    protected override void OnInitialized() =>
        Model ??= new() { ProductionDate = DateTime.UtcNow };

    private void Submit()
    {
        customValidation?.ClearErrors();

        var errors = new Dictionary<string, List<string>>();

        if (Model!.Classification == "Defense" &&
                string.IsNullOrEmpty(Model.Description))
        {
            errors.Add(nameof(Model.Description),
                new() { "For a 'Defense' ship classification, " +
                "'Description' is required." });
        }

        if (errors.Any())
        {
            customValidation?.DisplayErrors(errors);
        }
        else
        {
            Logger.LogInformation("Submit called: Processing the form");
        }
    }
}

Poznámka:

Jako alternativu k použití ověřovacích komponent je možné použít atributy ověření datových poznámek. Vlastní atributy použité u modelu formuláře se aktivují pomocí DataAnnotationsValidator komponenty. Při použití s ověřením serveru musí být atributy spustitelné na serveru. Další informace najdete v části Vlastní ověřovací atributy .

Ověření serveru pomocí komponenty validátoru

Tato část se zaměřuje na Blazor Web App scénáře, ale přístup pro jakýkoli typ aplikace, který používá ověřování serveru s webovým rozhraním API, používá stejný obecný přístup.

Tato část se zaměřuje na hostované Blazor WebAssembly scénáře, ale přístup pro jakýkoli typ aplikace, který používá ověřování serveru s webovým rozhraním API, využívá stejný obecný přístup.

Ověření serveru je podporováno kromě ověření klienta:

  • Zpracování ověření klienta ve formuláři s komponentou DataAnnotationsValidator
  • Když formulář předá ověření klienta (OnValidSubmit je volána), odešle EditContext.Model rozhraní API back-endového serveru pro zpracování formulářů.
  • Ověření modelu procesu na serveru
  • Rozhraní API serveru zahrnuje ověřování integrovaných datových poznámek architektury i vlastní logiku ověřování, kterou poskytl vývojář. Pokud ověření proběhne na serveru, zpracujte formulář a odešlete zpět stavový kód úspěchu (200 - OK). Pokud ověření selže, vraťte stavový kód chyby (400 - Bad Request) a chyby ověření pole.
  • Buď zakažte formulář při úspěchu, nebo zobrazte chyby.

Základní ověřování je užitečné v případech, kdy je model formuláře definován v rámci komponenty hostující formulář, a to buď jako členy přímo na komponentě, nebo v podtřídě. Použití komponenty validátoru se doporučuje, když se používá nezávislá třída modelu napříč několika komponentami.

Následující příklad je založen na:

Starship Umístěte model (Starship.cs) do projektu knihovny sdílených tříd, aby ho mohly používat projekty klienta i serveru. Přidejte nebo aktualizujte obor názvů tak, namespace BlazorSample.Sharedaby odpovídal oboru názvů sdílené aplikace (například). Vzhledem k tomu, že model vyžaduje datové poznámky, ověřte, že knihovna sdílených tříd používá sdílenou architekturu System.ComponentModel.Annotations nebo přidá balíček do sdíleného projektu.

Poznámka:

Pokyny k přidávání balíčků do aplikací .NET najdete v článcích v části Instalace a správa balíčků na webu Pracovní postup používání balíčků (dokumentace k NuGetu). Ověřte správné verze balíčků na NuGet.org.

V hlavním projektu Blazor Web Apppřidejte kontroler pro zpracování žádostí o ověření hvězdicové lodi a vrácení neúspěšných ověřovacích zpráv. Aktualizujte obory názvů v posledním using příkazu pro projekt knihovny sdílených tříd a namespace třídu kontroleru. Kromě ověření poznámek k datům klienta a serveru kontroler ověří, že je pro popis lodi zadaná hodnota (Description), pokud uživatel vybere Defense klasifikaci (Classification).

Starship Umístěte model (Starship.cs) do projektu řešení Shared tak, aby ho mohly používat jak klientské, tak serverové aplikace. Přidejte nebo aktualizujte obor názvů tak, namespace BlazorSample.Sharedaby odpovídal oboru názvů sdílené aplikace (například). Vzhledem k tomu, že model vyžaduje datové poznámky, přidejte System.ComponentModel.Annotations balíček do Shared projektu.

Poznámka:

Pokyny k přidávání balíčků do aplikací .NET najdete v článcích v části Instalace a správa balíčků na webu Pracovní postup používání balíčků (dokumentace k NuGetu). Ověřte správné verze balíčků na NuGet.org.

Server V projektu přidejte kontroler pro zpracování žádostí o ověření hvězdicové lodi a vrácení neúspěšných ověřovacích zpráv. Aktualizujte obory názvů v posledním using příkazu projektu Shared a namespace třídy kontroleru. Kromě ověření poznámek k datům klienta a serveru kontroler ověří, že je pro popis lodi zadaná hodnota (Description), pokud uživatel vybere Defense klasifikaci (Classification).

Ověření Defense klasifikace expedice probíhá pouze na serveru v kontroleru, protože nadcházející formulář neprovádí stejné ověření na straně klienta při odeslání formuláře na server. Ověřování serveru bez ověření klienta je běžné v aplikacích, které vyžadují ověřování uživatelských vstupů na serveru pomocí privátní obchodní logiky. Například soukromé informace z dat uložených pro uživatele můžou být nutné k ověření vstupu uživatele. Privátní data se samozřejmě nedají odeslat klientovi pro ověření klienta.

Poznámka:

Kontroler StarshipValidation v této části používá Microsoft Identity 2.0. Webové rozhraní API přijímá pouze tokeny pro uživatele, kteří mají pro toto rozhraní API obor "API.Access". Pokud se název oboru rozhraní API liší od API.Accessnázvu rozhraní API, vyžaduje se další přizpůsobení.

Další informace o zabezpečení najdete tady:

Controllers/StarshipValidation.cs:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using BlazorSample.Shared;

namespace BlazorSample.Server.Controllers;

[Authorize]
[ApiController]
[Route("[controller]")]
public class StarshipValidationController(
    ILogger<StarshipValidationController> logger) 
    : ControllerBase
{
    static readonly string[] scopeRequiredByApi = new[] { "API.Access" };

    [HttpPost]
    public async Task<IActionResult> Post(Starship model)
    {
        HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);

        try
        {
            if (model.Classification == "Defense" && 
                string.IsNullOrEmpty(model.Description))
            {
                ModelState.AddModelError(nameof(model.Description),
                    "For a 'Defense' ship " +
                    "classification, 'Description' is required.");
            }
            else
            {
                logger.LogInformation("Processing the form asynchronously");

                // async ...

                return Ok(ModelState);
            }
        }
        catch (Exception ex)
        {
            logger.LogError("Validation Error: {Message}", ex.Message);
        }

        return BadRequest(ModelState);
    }
}

Potvrďte nebo aktualizujte obor názvů předchozího kontroleru (BlazorSample.Server.Controllers) tak, aby odpovídal oboru názvů kontrolerů aplikace.

Pokud na serveru dojde k chybě ověření vazby modelu, ApiController vrátí (ApiControllerAttribute) obvykle výchozí chybnou odpověď požadavku s chybou ValidationProblemDetails. Odpověď obsahuje více dat než jen chyby ověření, jak je znázorněno v následujícím příkladu, když se neodesílají všechna pole Starfleet Starship Database formuláře a formulář selže s ověřením:

{
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errors": {
    "Id": ["The Id field is required."],
    "Classification": ["The Classification field is required."],
    "IsValidatedDesign": ["This form disallows unapproved ships."],
    "MaximumAccommodation": ["Accommodation invalid (1-100000)."]
  }
}

Poznámka:

Pokud chcete předvést předchozí odpověď JSON, musíte buď zakázat ověření klienta formuláře, aby bylo možné odeslat prázdný formulář pole, nebo použít nástroj k odeslání požadavku přímo na serverové rozhraní API, jako je například Firefox Browser Developer.

Pokud serverové rozhraní API vrátí předchozí výchozí odpověď JSON, může klient analyzovat odpověď v kódu vývojáře, aby získal podřízené položky errors uzlu pro zpracování chyb ověřování formulářů. Není vhodné napsat kód vývojáře, který soubor parsuje. Ruční analýza JSON vyžaduje vytvoření Dictionary<string, List<string>> chyb po volání ReadFromJsonAsync. V ideálním případě by serverové rozhraní API mělo vrátit pouze chyby ověření, jak ukazuje následující příklad:

{
  "Id": ["The Id field is required."],
  "Classification": ["The Classification field is required."],
  "IsValidatedDesign": ["This form disallows unapproved ships."],
  "MaximumAccommodation": ["Accommodation invalid (1-100000)."]
}

Pokud chcete upravit odpověď rozhraní API serveru tak, aby vracela pouze chyby ověření, změňte delegáta, který je vyvolán u akcí, které jsou v souboru opatřené poznámkami ApiControllerAttribute Program . Pro koncový bod rozhraní API (/StarshipValidation) vraťte s znakem BadRequestObjectResult ModelStateDictionary. Pro všechny ostatní koncové body rozhraní API zachovejte výchozí chování vrácením výsledku objektu s novým ValidationProblemDetails.

Microsoft.AspNetCore.Mvc Přidejte obor názvů na začátek Program souboru v hlavním projektu objektu Blazor Web App:

using Microsoft.AspNetCore.Mvc;

Program Do souboru přidejte nebo aktualizujte následující AddControllersWithViews metodu rozšíření a přidejte následující voláníConfigureApiBehaviorOptions:

builder.Services.AddControllersWithViews()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.InvalidModelStateResponseFactory = context =>
        {
            if (context.HttpContext.Request.Path == "/StarshipValidation")
            {
                return new BadRequestObjectResult(context.ModelState);
            }
            else
            {
                return new BadRequestObjectResult(
                    new ValidationProblemDetails(context.ModelState));
            }
        };
    });

Pokud přidáváte kontrolery do hlavního Blazor Web App projektu prvního projektu, namapujte koncové body kontroleru při umístění předchozího kódu, který registruje služby pro kontrolery. Následující příklad používá výchozí trasy kontroleru:

app.MapDefaultControllerRoute();

Poznámka:

Předchozí příklad explicitně zaregistruje služby kontroleru voláním AddControllersWithViews automatického zmírnění útoků XSRF/CSRF (Cross-Site Request Forgery). Pokud použijete AddControllerspouze funkci antiforgery, není povolena automaticky.

Další informace o chybách chyb směrování a ověřování kontroleru najdete v následujících zdrojích informací:

.Client V projektu přidejte komponentu CustomValidation zobrazenou v části Součásti validátoru. Aktualizujte obor názvů tak, namespace BlazorSample.Clientaby odpovídal aplikaci (například).

.Client V projektu se formulář aktualizuje tak, Starfleet Starship Database aby zobrazoval chyby ověření serveru pomocí CustomValidation komponenty. Když rozhraní API serveru vrátí ověřovací zprávy, přidají se do CustomValidation komponenty ValidationMessageStore. Chyby jsou k dispozici ve formuláři EditContext pro zobrazení souhrnem ověření formuláře.

V následující komponentě aktualizujte obor názvů sdíleného projektu (@using BlazorSample.Shared) na obor názvů sdíleného projektu. Všimněte si, že formulář vyžaduje autorizaci, takže uživatel musí být přihlášený k aplikaci, aby se k formuláři dostal.

Microsoft.AspNetCore.Mvc Přidejte obor názvů na začátek Program souboru v Server aplikaci:

using Microsoft.AspNetCore.Mvc;

Program V souboru vyhledejte rozšiřující metodu AddControllersWithViews a přidejte následující voláníConfigureApiBehaviorOptions:

builder.Services.AddControllersWithViews()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.InvalidModelStateResponseFactory = context =>
        {
            if (context.HttpContext.Request.Path == "/StarshipValidation")
            {
                return new BadRequestObjectResult(context.ModelState);
            }
            else
            {
                return new BadRequestObjectResult(
                    new ValidationProblemDetails(context.ModelState));
            }
        };
    });

Poznámka:

Předchozí příklad explicitně zaregistruje služby kontroleru voláním AddControllersWithViews automatického zmírnění útoků XSRF/CSRF (Cross-Site Request Forgery). Pokud použijete AddControllerspouze funkci antiforgery, není povolena automaticky.

Client V projektu přidejte komponentu CustomValidation zobrazenou v části Součásti validátoru. Aktualizujte obor názvů tak, namespace BlazorSample.Clientaby odpovídal aplikaci (například).

Client V projektu se formulář aktualizuje tak, Starfleet Starship Database aby zobrazoval chyby ověření serveru pomocí CustomValidation komponenty. Když rozhraní API serveru vrátí ověřovací zprávy, přidají se do CustomValidation komponenty ValidationMessageStore. Chyby jsou k dispozici ve formuláři EditContext pro zobrazení souhrnem ověření formuláře.

V následující komponentě aktualizujte obor názvů Shared projektu (@using BlazorSample.Shared) na obor názvů sdíleného projektu. Všimněte si, že formulář vyžaduje autorizaci, takže uživatel musí být přihlášený k aplikaci, aby se k formuláři dostal.

Starship10.razor:

Poznámka:

Formuláře založené na EditForm automatickém povolení podpory antiforgery Kontroler by měl používat AddControllersWithViews k registraci služeb kontroleru a automaticky povolit podporu antiforgery pro webové rozhraní API.

@page "/starship-10"
@rendermode InteractiveWebAssembly
@using System.Net
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using BlazorSample.Shared
@attribute [Authorize]
@inject HttpClient Http
@inject ILogger<Starship10> Logger

<h1>Starfleet Starship Database</h1>

<h2>New Ship Entry Form</h2>

<EditForm FormName="Starship10" Model="Model" OnValidSubmit="Submit">
    <DataAnnotationsValidator />
    <CustomValidation @ref="customValidation" />
    <ValidationSummary />
    <div>
        <label>
            Identifier: 
            <InputText @bind-Value="Model!.Id" disabled="@disabled" />
        </label>
    </div>
    <div>
        <label>
            Description (optional):
            <InputTextArea @bind-Value="Model!.Description" 
                disabled="@disabled" />
        </label>
    </div>
    <div>
        <label>
            Primary Classification:
            <InputSelect @bind-Value="Model!.Classification" disabled="@disabled">
                <option value="">Select classification ...</option>
                <option value="Exploration">Exploration</option>
                <option value="Diplomacy">Diplomacy</option>
                <option value="Defense">Defense</option>
            </InputSelect>
        </label>
    </div>
    <div>
        <label>
            Maximum Accommodation:
            <InputNumber @bind-Value="Model!.MaximumAccommodation" 
                disabled="@disabled" />
        </label>
    </div>
    <div>
        <label>
            Engineering Approval:
            <InputCheckbox @bind-Value="Model!.IsValidatedDesign" 
                disabled="@disabled" />
        </label>
    </div>
    <div>
        <label>
            Production Date:
            <InputDate @bind-Value="Model!.ProductionDate" disabled="@disabled" />
        </label>
    </div>
    <div>
        <button type="submit" disabled="@disabled">Submit</button>
    </div>
    <div style="@messageStyles">
        @message
    </div>
</EditForm>

@code {
    private CustomValidation? customValidation;
    private bool disabled;
    private string? message;
    private string messageStyles = "visibility:hidden";

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

    protected override void OnInitialized() => 
        Model ??= new() { ProductionDate = DateTime.UtcNow };

    private async Task Submit(EditContext editContext)
    {
        customValidation?.ClearErrors();

        try
        {
            var response = await Http.PostAsJsonAsync<Starship>(
                "StarshipValidation", (Starship)editContext.Model);

            var errors = await response.Content
                .ReadFromJsonAsync<Dictionary<string, List<string>>>() ?? 
                new Dictionary<string, List<string>>();

            if (response.StatusCode == HttpStatusCode.BadRequest && 
                errors.Any())
            {
                customValidation?.DisplayErrors(errors);
            }
            else if (!response.IsSuccessStatusCode)
            {
                throw new HttpRequestException(
                    $"Validation failed. Status Code: {response.StatusCode}");
            }
            else
            {
                disabled = true;
                messageStyles = "color:green";
                message = "The form has been processed.";
            }
        }
        catch (AccessTokenNotAvailableException ex)
        {
            ex.Redirect();
        }
        catch (Exception ex)
        {
            Logger.LogError("Form processing error: {Message}", ex.Message);
            disabled = true;
            messageStyles = "color:red";
            message = "There was an error processing the form.";
        }
    }
}

Projekt .Client Blazor Web App musí také zaregistrovat HttpClient požadavky HTTP POST na kontroler back-endového webového rozhraní API. Potvrďte nebo přidejte do .Client souboru projektu Program následující:

builder.Services.AddScoped(sp => 
    new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

Předchozí příklad nastaví základní adresu na builder.HostEnvironment.BaseAddress (IWebAssemblyHostEnvironment.BaseAddress), která získá základní adresu aplikace a obvykle se odvozuje od <base> hodnoty značky href na stránce hostitele.

@page "/starship-10"
@using System.Net
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using BlazorSample.Shared
@attribute [Authorize]
@inject HttpClient Http
@inject ILogger<Starship10> Logger

<h1>Starfleet Starship Database</h1>

<h2>New Ship Entry Form</h2>

<EditForm Model="Model" OnValidSubmit="Submit">
    <DataAnnotationsValidator />
    <CustomValidation @ref="customValidation" />
    <ValidationSummary />
    <div>
        <label>
            Identifier: 
            <InputText @bind-Value="Model!.Id" disabled="@disabled" />
        </label>
    </div>
    <div>
        <label>
            Description (optional):
            <InputTextArea @bind-Value="Model!.Description" 
                disabled="@disabled" />
        </label>
    </div>
    <div>
        <label>
            Primary Classification:
            <InputSelect @bind-Value="Model!.Classification" disabled="@disabled">
                <option value="">Select classification ...</option>
                <option value="Exploration">Exploration</option>
                <option value="Diplomacy">Diplomacy</option>
                <option value="Defense">Defense</option>
            </InputSelect>
        </label>
    </div>
    <div>
        <label>
            Maximum Accommodation:
            <InputNumber @bind-Value="Model!.MaximumAccommodation" 
                disabled="@disabled" />
        </label>
    </div>
    <div>
        <label>
            Engineering Approval:
            <InputCheckbox @bind-Value="Model!.IsValidatedDesign" 
                disabled="@disabled" />
        </label>
    </div>
    <div>
        <label>
            Production Date:
            <InputDate @bind-Value="Model!.ProductionDate" disabled="@disabled" />
        </label>
    </div>
    <div>
        <button type="submit" disabled="@disabled">Submit</button>
    </div>
    <div style="@messageStyles">
        @message
    </div>
</EditForm>

@code {
    private CustomValidation? customValidation;
    private bool disabled;
    private string? message;
    private string messageStyles = "visibility:hidden";

    public Starship? Model { get; set; }

    protected override void OnInitialized() => 
        Model ??= new() { ProductionDate = DateTime.UtcNow };

    private async Task Submit(EditContext editContext)
    {
        customValidation?.ClearErrors();

        try
        {
            var response = await Http.PostAsJsonAsync<Starship>(
                "StarshipValidation", (Starship)editContext.Model);

            var errors = await response.Content
                .ReadFromJsonAsync<Dictionary<string, List<string>>>() ?? 
                new Dictionary<string, List<string>>();

            if (response.StatusCode == HttpStatusCode.BadRequest && 
                errors.Any())
            {
                customValidation?.DisplayErrors(errors);
            }
            else if (!response.IsSuccessStatusCode)
            {
                throw new HttpRequestException(
                    $"Validation failed. Status Code: {response.StatusCode}");
            }
            else
            {
                disabled = true;
                messageStyles = "color:green";
                message = "The form has been processed.";
            }
        }
        catch (AccessTokenNotAvailableException ex)
        {
            ex.Redirect();
        }
        catch (Exception ex)
        {
            Logger.LogError("Form processing error: {Message}", ex.Message);
            disabled = true;
            messageStyles = "color:red";
            message = "There was an error processing the form.";
        }
    }
}

Poznámka:

Jako alternativu k použití ověřovací komponenty lze použít atributy ověření datových poznámek. Vlastní atributy použité u modelu formuláře se aktivují pomocí DataAnnotationsValidator komponenty. Při použití s ověřením serveru musí být atributy spustitelné na serveru. Další informace najdete v části Vlastní ověřovací atributy .

Poznámka:

Přístup k ověření serveru v této části je vhodný pro některý z příkladů hostovaného Blazor WebAssembly řešení v této sadě dokumentace:

InputText na základě vstupní události

InputText Pomocí této komponenty vytvořte vlastní komponentu, která místo události () onchange používá oninput událost (inputchange). input Použití ověření pole události aktivuje při každém stisknutí klávesy.

Následující CustomInputText komponenta dědí komponentu architektury InputText a nastaví vazbu událostí na oninput událost (input).

CustomInputText.razor:

@inherits InputText

<input @attributes="AdditionalAttributes" 
       class="@CssClass" 
       @bind="CurrentValueAsString" 
       @bind:event="oninput" />

Komponentu CustomInputText lze použít kdekoli InputText . Následující komponenta používá sdílenou CustomInputText komponentu.

Starship11.razor:

@page "/starship-11"
@using System.ComponentModel.DataAnnotations
@inject ILogger<Starship11> Logger

<EditForm Model="Model" OnValidSubmit="Submit" FormName="Starship11">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <div>
        <label>
            Identifier: 
            <CustomInputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

<div>
    CurrentValue: @Model?.Id
</div>

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

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

    private void Submit() => Logger.LogInformation("Submit: Processing form");

    public class Starship
    {
        [Required]
        [StringLength(10, ErrorMessage = "Id is too long.")]
        public string? Id { get; set; }
    }
}
@page "/starship-11"
@using System.ComponentModel.DataAnnotations
@inject ILogger<Starship11> Logger

<EditForm Model="Model" OnValidSubmit="Submit" FormName="Starship11">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <div>
        <label>
            Identifier: 
            <CustomInputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

<div>
    CurrentValue: @Model?.Id
</div>

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

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

    private void Submit() => Logger.LogInformation("Submit: Processing form");

    public class Starship
    {
        [Required]
        [StringLength(10, ErrorMessage = "Id is too long.")]
        public string? Id { get; set; }
    }
}
@page "/starship-11"
@using System.ComponentModel.DataAnnotations
@inject ILogger<Starship11> Logger

<EditForm Model="Model" OnValidSubmit="Submit">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <CustomInputText @bind-Value="Model!.Id" />
    <button type="submit">Submit</button>
</EditForm>

<div>
    CurrentValue: @Model?.Id
</div>

@code {
    public Starship? Model { get; set; }

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

    private void Submit()
    {
        Logger.LogInformation("Submit called: Processing the form");
    }

    public class Starship
    {
        [Required]
        [StringLength(10, ErrorMessage = "Id is too long.")]
        public string? Id { get; set; }
    }
}

Komponenty souhrnu ověření a ověřovací zprávy

Komponenta ValidationSummary shrnuje všechny ověřovací zprávy, které jsou podobné pomocné rutině značky souhrnu ověření:

<ValidationSummary />

Výstupní ověřovací zprávy pro konkrétní model s parametrem Model :

<ValidationSummary Model="Model" />

Komponenta ValidationMessage<TValue> zobrazí ověřovací zprávy pro konkrétní pole, které je podobné pomocné rutině značky ověřovací zprávy. Zadejte pole pro ověření pomocí atributu For a výraz lambda s pojmenováním vlastnosti modelu:

<ValidationMessage For="@(() => Model!.MaximumAccommodation)" />

ValidationSummary Komponenty ValidationMessage<TValue> podporují libovolné atributy. Do vygenerovaného <div> nebo <ul> elementu se přidá jakýkoli atribut, který neodpovídá parametru komponenty.

Umožňuje řídit styl ověřovacích zpráv v šabloně stylů aplikace (wwwroot/css/app.css nebo wwwroot/css/site.css). Výchozí validation-message třída nastaví barvu textu ověřovacích zpráv na červenou:

.validation-message {
    color: red;
}

Určení, jestli je pole formuláře platné

Slouží EditContext.IsValid k určení, zda je pole platné bez získání ověřovacích zpráv.

Podporováno, ale nedoporučuje se:

var isValid = !editContext.GetValidationMessages(fieldIdentifier).Any();

Doporučený:

var isValid = editContext.IsValid(fieldIdentifier);

Vlastní ověřovací atributy

Chcete-li zajistit správné přidružení výsledku ověření k poli při použití vlastního ověřovacího atributu, předejte kontext MemberName ověření při vytváření ValidationResult.

CustomValidator.cs:

using System;
using System.ComponentModel.DataAnnotations;

public class CustomValidator : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, 
        ValidationContext validationContext)
    {
        ...

        return new ValidationResult("Validation message to user.",
            new[] { validationContext.MemberName });
    }
}

Vložte služby do vlastních ověřovacích atributů prostřednictvím .ValidationContext Následující příklad ukazuje formulář chef salátu, který ověřuje vstup uživatele pomocí injektáže závislostí (DI).

Třída SaladChef označuje schválený seznam složek hvězdicové lodi pro ten forward salát.

SaladChef.cs:

namespace BlazorSample;

public class SaladChef
{
    public string[] SaladToppers = { "Horva", "Kanda Root", "Krintar", "Plomeek",
        "Syto Bean" };
}

Zaregistrujte SaladChef se v kontejneru DI aplikace v Program souboru:

builder.Services.AddTransient<SaladChef>();

Metoda IsValid následující SaladChefValidatorAttribute třídy získá SaladChef službu z DI ke kontrole vstupu uživatele.

SaladChefValidatorAttribute.cs:

using System.ComponentModel.DataAnnotations;

namespace BlazorSample;

public class SaladChefValidatorAttribute : ValidationAttribute
{
    protected override ValidationResult? IsValid(object? value,
        ValidationContext validationContext)
    {
        var saladChef = validationContext.GetRequiredService<SaladChef>();

        if (saladChef.SaladToppers.Contains(value?.ToString()))
        {
            return ValidationResult.Success;
        }

        return new ValidationResult("Is that a Vulcan salad topper?! " +
            "The following toppers are available for a Ten Forward salad: " +
            string.Join(", ", saladChef.SaladToppers));
    }
}

Následující komponenta ověřuje uživatelský vstup použitím SaladChefValidatorAttribute ([SaladChefValidator]) na řetězec složky salátu (SaladIngredient).

Starship12.razor:

@page "/starship-12"
@inject SaladChef SaladChef

<EditForm Model="this" autocomplete="off" FormName="Starship12">
    <DataAnnotationsValidator />
    <div>
        <label>
            Salad topper (@saladToppers):
            <input @bind="SaladIngredient" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
    <ul>
        @foreach (var message in context.GetValidationMessages())
        {
            <li class="validation-message">@message</li>
        }
    </ul>
</EditForm>

@code {
    private string? saladToppers;

    [SaladChefValidator]
    public string? SaladIngredient { get; set; }

    protected override void OnInitialized() =>
        saladToppers ??= string.Join(", ", SaladChef.SaladToppers);
}
@page "/starship-12"
@inject SaladChef SaladChef

<EditForm Model="this" autocomplete="off" FormName="Starship12">
    <DataAnnotationsValidator />
    <div>
        <label>
            Salad topper (@saladToppers):
            <input @bind="SaladIngredient" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
    <ul>
        @foreach (var message in context.GetValidationMessages())
        {
            <li class="validation-message">@message</li>
        }
    </ul>
</EditForm>

@code {
    private string? saladToppers;

    [SaladChefValidator]
    public string? SaladIngredient { get; set; }

    protected override void OnInitialized() =>
        saladToppers ??= string.Join(", ", SaladChef.SaladToppers);
}
@page "/starship-12"
@inject SaladChef SaladChef

<EditForm Model="this" autocomplete="off">
    <DataAnnotationsValidator />
    <p>
        <label>
            Salad topper (@saladToppers):
            <input @bind="SaladIngredient" />
        </label>
    </p>
    <button type="submit">Submit</button>
    <ul>
        @foreach (var message in context.GetValidationMessages())
        {
            <li class="validation-message">@message</li>
        }
    </ul>
</EditForm>

@code {
    private string? saladToppers;

    [SaladChefValidator]
    public string? SaladIngredient { get; set; }

    protected override void OnInitialized() => 
        saladToppers ??= string.Join(", ", SaladChef.SaladToppers);
}

Vlastní ověřovací atributy třídy CSS

Atributy vlastních ověřovacích tříd CSS jsou užitečné při integraci s architekturami CSS, například Bootstrap.

Pokud chcete zadat vlastní atributy třídy CSS, začněte zadáním stylů CSS pro vlastní ověření. V následujícím příkladu jsou zadány platné (validField) a neplatné (invalidField) styly.

Do šablony stylů aplikace přidejte následující třídy CSS:

.validField {
    border-color: lawngreen;
}

.invalidField {
    background-color: tomato;
}

Vytvořte třídu odvozenou z FieldCssClassProvider kontroly ověřovacích zpráv polí a použije příslušný platný nebo neplatný styl.

CustomFieldClassProvider.cs:

using Microsoft.AspNetCore.Components.Forms;

public class CustomFieldClassProvider : FieldCssClassProvider
{
    public override string GetFieldCssClass(EditContext editContext, 
        in FieldIdentifier fieldIdentifier)
    {
        var isValid = editContext.IsValid(fieldIdentifier);

        return isValid ? "validField" : "invalidField";
    }
}
using Microsoft.AspNetCore.Components.Forms;

public class CustomFieldClassProvider : FieldCssClassProvider
{
    public override string GetFieldCssClass(EditContext editContext, 
        in FieldIdentifier fieldIdentifier)
    {
        var isValid = !editContext.GetValidationMessages(fieldIdentifier).Any();

        return isValid ? "validField" : "invalidField";
    }
}

CustomFieldClassProvider Nastavte třídu jako zprostředkovatele třídy CSS pole v instanci formuláře EditContext s SetFieldCssClassProvider.

Starship13.razor:

@page "/starship-13"
@using System.ComponentModel.DataAnnotations
@inject ILogger<Starship13> Logger

<EditForm EditContext="editContext" OnValidSubmit="Submit" FormName="Starship13">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <div>
        <label>
            Identifier: 
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    private EditContext? editContext;

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

    protected override void OnInitialized()
    {
        Model ??= new();
        editContext = new(Model);
        editContext.SetFieldCssClassProvider(new CustomFieldClassProvider());
    }

    private void Submit() => Logger.LogInformation("Submit: Processing form");

    public class Starship
    {
        [Required]
        [StringLength(10, ErrorMessage = "Id is too long.")]
        public string? Id { get; set; }
    }
}
@page "/starship-13"
@using System.ComponentModel.DataAnnotations
@inject ILogger<Starship13> Logger

<EditForm EditContext="editContext" OnValidSubmit="Submit" FormName="Starship13">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <div>
        <label>
            Identifier: 
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    private EditContext? editContext;

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

    protected override void OnInitialized()
    {
        Model ??= new();
        editContext = new(Model);
        editContext.SetFieldCssClassProvider(new CustomFieldClassProvider());
    }

    private void Submit() => Logger.LogInformation("Submit: Processing form");

    public class Starship
    {
        [Required]
        [StringLength(10, ErrorMessage = "Id is too long.")]
        public string? Id { get; set; }
    }
}
@page "/starship-13"
@using System.ComponentModel.DataAnnotations
@inject ILogger<Starship13> Logger

<EditForm EditContext="editContext" OnValidSubmit="Submit">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <InputText @bind-Value="Model!.Id" />
    <button type="submit">Submit</button>
</EditForm>

@code {
    private EditContext? editContext;

    public Starship? Model { get; set; }

    protected override void OnInitialized()
    {
        Model ??= new();
        editContext = new(Model);
        editContext.SetFieldCssClassProvider(new CustomFieldClassProvider());
    }

    private void Submit()
    {
        Logger.LogInformation("Submit called: Processing the form");
    }

    public class Starship
    {
        [Required]
        [StringLength(10, ErrorMessage = "Id is too long.")]
        public string? Id { get; set; }
    }
}

Předchozí příklad zkontroluje platnost všech polí formuláře a použije styl pro každé pole. Pokud by formulář měl použít pouze vlastní styly na podmnožinu polí, podmíněné CustomFieldClassProvider použití stylů. Následující CustomFieldClassProvider2 příklad aplikuje styl pouze na Name pole. Pro všechna pole s názvy, která neodpovídají Name, string.Empty je vrácena a není použit žádný styl. Pomocí reflexe se pole shoduje s vlastností nebo názvem pole člena modelu, nikoli s přiřazenou entitou id HTML.

CustomFieldClassProvider2.cs:

using Microsoft.AspNetCore.Components.Forms;

public class CustomFieldClassProvider2 : FieldCssClassProvider
{
    public override string GetFieldCssClass(EditContext editContext,
        in FieldIdentifier fieldIdentifier)
    {
        if (fieldIdentifier.FieldName == "Name")
        {
            var isValid = editContext.IsValid(fieldIdentifier);

            return isValid ? "validField" : "invalidField";
        }

        return string.Empty;
    }
}
using Microsoft.AspNetCore.Components.Forms;

public class CustomFieldClassProvider2 : FieldCssClassProvider
{
    public override string GetFieldCssClass(EditContext editContext,
        in FieldIdentifier fieldIdentifier)
    {
        if (fieldIdentifier.FieldName == "Name")
        {
            var isValid = !editContext.GetValidationMessages(fieldIdentifier).Any();

            return isValid ? "validField" : "invalidField";
        }

        return string.Empty;
    }
}

Poznámka:

Při porovnávání názvu pole v předchozím příkladu se rozlišují malá a velká písmena, takže člen vlastnosti modelu označený jako "Name" musí odpovídat podmíněné kontrole "Name":

  • Správně odpovídá: fieldId.FieldName == "Name"
  • Nedaří se shodovat: fieldId.FieldName == "name"
  • Nedaří se shodovat: fieldId.FieldName == "NAME"
  • Nedaří se shodovat: fieldId.FieldName == "nAmE"

Přidejte další vlastnost, Modelnapříklad:

[StringLength(10, ErrorMessage = "Description is too long.")]
public string? Description { get; set; } 

Description Přidejte do CustomValidationForm formuláře komponenty:

<InputText @bind-Value="Model!.Description" />

EditContext Aktualizujte instanci v metodě komponenty OnInitialized tak, aby používala nového zprostředkovatele třídy CSS pole:

editContext?.SetFieldCssClassProvider(new CustomFieldClassProvider2());

Vzhledem k tomu, že u pole není použita Description ověřovací třída šablon stylů CSS, není stylovaná. Ověřování polí se ale spouští normálně. Pokud je zadáno více než 10 znaků, souhrn ověření označuje chybu:

Popis je příliš dlouhý.

V následujícím příkladu:

  • Vlastní styl CSS se použije u Name pole.

  • Všechna ostatní pole používají logiku podobnou Blazorvýchozí logice a používají Blazorvýchozí styly ověřování šablon stylů modified CSS s valid nebo invalid. Všimněte si, že u výchozích stylů je nemusíte přidávat do šablony stylů aplikace, pokud je aplikace založená Blazor na šabloně projektu. U aplikací, které nejsou založené na Blazor šabloně projektu, je možné do šablony stylů aplikace přidat výchozí styly:

    .valid.modified:not([type=checkbox]) {
        outline: 1px solid #26b050;
    }
    
    .invalid {
        outline: 1px solid red;
    }
    

CustomFieldClassProvider3.cs:

using Microsoft.AspNetCore.Components.Forms;

public class CustomFieldClassProvider3 : FieldCssClassProvider
{
    public override string GetFieldCssClass(EditContext editContext,
        in FieldIdentifier fieldIdentifier)
    {
        var isValid = editContext.IsValid(fieldIdentifier);

        if (fieldIdentifier.FieldName == "Name")
        {
            return isValid ? "validField" : "invalidField";
        }
        else
        {
            if (editContext.IsModified(fieldIdentifier))
            {
                return isValid ? "modified valid" : "modified invalid";
            }
            else
            {
                return isValid ? "valid" : "invalid";
            }
        }
    }
}
using Microsoft.AspNetCore.Components.Forms;

public class CustomFieldClassProvider3 : FieldCssClassProvider
{
    public override string GetFieldCssClass(EditContext editContext,
        in FieldIdentifier fieldIdentifier)
    {
        var isValid = !editContext.GetValidationMessages(fieldIdentifier).Any();

        if (fieldIdentifier.FieldName == "Name")
        {
            return isValid ? "validField" : "invalidField";
        }
        else
        {
            if (editContext.IsModified(fieldIdentifier))
            {
                return isValid ? "modified valid" : "modified invalid";
            }
            else
            {
                return isValid ? "valid" : "invalid";
            }
        }
    }
}

EditContext Aktualizujte instanci v metodě komponenty OnInitialized tak, aby používala předchozího zprostředkovatele třídy CSS pole:

editContext.SetFieldCssClassProvider(new CustomFieldClassProvider3());

Pomocí CustomFieldClassProvider3:

  • Pole Name používá vlastní styly css aplikace.
  • Pole Description používá logiku podobnou Blazorlogice a Blazorvýchozí styly ověřování ŠABLON STYLŮ CSS.

Ověřování na úrovni třídy s využitím IValidatableObject

Ověřování na úrovni třídy s IValidatableObject využitím (dokumentace k rozhraní API) se podporuje pro Blazor modely formulářů. IValidatableObject Ověření se spustí pouze při odeslání formuláře a pouze v případě, že se úspěšně provede všechny ostatní ověření.

Blazor Ověřovací balíček datových poznámek

Jedná se Microsoft.AspNetCore.Components.DataAnnotations.Validation o balíček, který vyplní mezery v prostředí ověřování pomocí DataAnnotationsValidator komponenty. Balíček je aktuálně experimentální.

Upozorňující

Balíček Microsoft.AspNetCore.Components.DataAnnotations.Validation má nejnovější verzi release candidate na NuGet.org. V tuto chvíli pokračujte v používání experimentálního balíčku Release Candidate. Experimentální funkce jsou k dispozici pro účely zkoumání životaschopnosti funkcí a nemusí být součástí stabilní verze. Další aktualizace najdete v úložišti Oznámení Na GitHubudotnet/aspnetcore, v úložišti GitHub nebo v tomto tématu.

Atribut [CompareProperty]

S CompareAttribute komponentou DataAnnotationsValidator nefunguje dobře, protože DataAnnotationsValidator výsledek ověření nepřidružuje ke konkrétnímu členu. To může vést k nekonzistentnímu chování mezi ověřováním na úrovni pole a ověřením celého modelu při odeslání. Experimentální Microsoft.AspNetCore.Components.DataAnnotations.Validation balíček zavádí další ověřovací atribut, ComparePropertyAttributekterý funguje s těmito omezeními. V aplikaci [CompareProperty] je přímá náhrada atributu[Compare].Blazor

Vnořené modely, typy kolekcí a komplexní typy

Blazor poskytuje podporu pro ověřování vstupu formuláře pomocí datových poznámek s integrovaným DataAnnotationsValidator. DataAnnotationsValidator Pouze ověří vlastnosti nejvyšší úrovně modelu vázaného na formulář, který není vlastností kolekce nebo komplexního typu.

K ověření celého grafu objektu vázaného modelu, včetně vlastností kolekce a komplexního typu, použijte ObjectGraphDataAnnotationsValidator experimentální Microsoft.AspNetCore.Components.DataAnnotations.Validation balíček:

<EditForm ...>
    <ObjectGraphDataAnnotationsValidator />
    ...
</EditForm>

Přidávání poznámek k vlastnostem modelu pomocí [ValidateComplexType]. V následujících třídách ShipDescription modelu třída obsahuje další datové poznámky k ověření, kdy je model svázán s formulářem:

Starship.cs:

using System;
using System.ComponentModel.DataAnnotations;

public class Starship
{
    ...

    [ValidateComplexType]
    public ShipDescription ShipDescription { get; set; } = new();

    ...
}

ShipDescription.cs:

using System;
using System.ComponentModel.DataAnnotations;

public class ShipDescription
{
    [Required]
    [StringLength(40, ErrorMessage = "Description too long (40 char).")]
    public string? ShortDescription { get; set; }

    [Required]
    [StringLength(240, ErrorMessage = "Description too long (240 char).")]
    public string? LongDescription { get; set; }
}

Povolení tlačítka odeslat na základě ověření formuláře

Pokud chcete povolit a zakázat tlačítko odeslat na základě ověření formuláře, použijte následující příklad:

  • Používá zkrácenou verzi dřívějšího Starfleet Starship Database formuláře (Starship3součást) části Příklad formuláře článku Vstupní komponenty, která přijímá pouze hodnotu pro ID lodi. Ostatní Starship vlastnosti obdrží platné výchozí hodnoty při vytvoření instance Starship typu.
  • Použije formulář EditContext k přiřazení modelu při inicializaci komponenty.
  • Ověří formulář v zpětném volání kontextu OnFieldChanged a povolí a zakáže tlačítko odeslat.
  • Implementuje IDisposable a odhlásí obslužnou rutinu Dispose události v metodě. Další informace najdete v tématu Životní cyklus komponent ASP.NET Core Razor.

Poznámka:

Při přiřazování k objektu EditForm.EditContext, nepřiřaďte EditForm.Model mu EditFormani .

Starship14.razor:

@page "/starship-14"
@implements IDisposable
@inject ILogger<Starship14> Logger

<EditForm EditContext="editContext" OnValidSubmit="Submit" FormName="Starship14">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <div>
        <label>
            Identifier:
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <button type="submit" disabled="@formInvalid">Submit</button>
    </div>
</EditForm>

@code {
    private bool formInvalid = false;
    private EditContext? editContext;

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

    protected override void OnInitialized()
    {
        Model ??=
            new()
                {
                    Id = "NCC-1701",
                    Classification = "Exploration",
                    MaximumAccommodation = 150,
                    IsValidatedDesign = true,
                    ProductionDate = new DateTime(2245, 4, 11)
                };
        editContext = new(Model);
        editContext.OnFieldChanged += HandleFieldChanged;
    }

    private void HandleFieldChanged(object? sender, FieldChangedEventArgs e)
    {
        if (editContext is not null)
        {
            formInvalid = !editContext.Validate();
            StateHasChanged();
        }
    }

    private void Submit() => Logger.LogInformation("Submit: Processing form");

    public void Dispose()
    {
        if (editContext is not null)
        {
            editContext.OnFieldChanged -= HandleFieldChanged;
        }
    }
}
@page "/starship-14"
@implements IDisposable
@inject ILogger<Starship14> Logger

<EditForm EditContext="editContext" OnValidSubmit="Submit" FormName="Starship14">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <div>
        <label>
            Identifier:
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <button type="submit" disabled="@formInvalid">Submit</button>
    </div>
</EditForm>

@code {
    private bool formInvalid = false;
    private EditContext? editContext;

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

    protected override void OnInitialized()
    {
        Model ??=
            new()
                {
                    Id = "NCC-1701",
                    Classification = "Exploration",
                    MaximumAccommodation = 150,
                    IsValidatedDesign = true,
                    ProductionDate = new DateTime(2245, 4, 11)
                };
        editContext = new(Model);
        editContext.OnFieldChanged += HandleFieldChanged;
    }

    private void HandleFieldChanged(object? sender, FieldChangedEventArgs e)
    {
        if (editContext is not null)
        {
            formInvalid = !editContext.Validate();
            StateHasChanged();
        }
    }

    private void Submit() => Logger.LogInformation("Submit: Processing form");

    public void Dispose()
    {
        if (editContext is not null)
        {
            editContext.OnFieldChanged -= HandleFieldChanged;
        }
    }
}
@page "/starship-14"
@implements IDisposable
@inject ILogger<Starship14> Logger

<EditForm EditContext="editContext" OnValidSubmit="Submit">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <div>
        <label>
            Identifier: 
            <InputText @bind-Value="Model!.Id" />
        </label>
    </div>
    <div>
        <button type="submit" disabled="@formInvalid">Submit</button>
    </div>
</EditForm>

@code {
    private bool formInvalid = false;
    private EditContext? editContext;

    private Starship? Model { get; set; }

    protected override void OnInitialized()
    {
        Model ??=
            new()
            {
                Id = "NCC-1701",
                Classification = "Exploration",
                MaximumAccommodation = 150,
                IsValidatedDesign = true,
                ProductionDate = new DateTime(2245, 4, 11)
            };
        editContext = new(Model);
        editContext.OnFieldChanged += HandleFieldChanged;
    }

    private void HandleFieldChanged(object? sender, FieldChangedEventArgs e)
    {
        if (editContext is not null)
        {
            formInvalid = !editContext.Validate();
            StateHasChanged();
        }
    }

    private void Submit()
    {
        Logger.LogInformation("Submit called: Processing the form");
    }

    public void Dispose()
    {
        if (editContext is not null)
        {
            editContext.OnFieldChanged -= HandleFieldChanged;
        }
    }
}

Pokud formulář není předem načten s platnými hodnotami a chcete tlačítko při načtení formuláře zakázatSubmit, nastavte na truehodnotu formInvalid .

Vedlejším účinkem předchozího přístupu je, že souhrn ověření (ValidationSummary součást) je naplněn neplatnými poli poté, co uživatel pracuje s libovolným polem. Tento scénář můžete vyřešit některým z následujících způsobů:

  • Nepoužívejte komponentu ValidationSummary ve formuláři.
  • Zviditelnit komponentu ValidationSummary , když je vybráno tlačítko odeslat (například v Submit metodě).
<EditForm ... EditContext="editContext" OnValidSubmit="Submit" ...>
    <DataAnnotationsValidator />
    <ValidationSummary style="@displaySummary" />

    ...

    <button type="submit" disabled="@formInvalid">Submit</button>
</EditForm>

@code {
    private string displaySummary = "display:none";

    ...

    private void Submit()
    {
        displaySummary = "display:block";
    }
}