sprawdzanie poprawności formularzy ASP.NET Core Blazor
Uwaga
Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.
Ważne
Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.
Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.
W tym artykule wyjaśniono, jak używać walidacji w Blazor formularzach.
Walidacja formularza
W podstawowych scenariuszach weryfikacji formularzy EditForm wystąpienie może używać zadeklarowanych EditContext wystąpień i ValidationMessageStore do sprawdzania poprawności pól formularza. Procedura obsługi zdarzenia OnValidationRequested EditContext wykonuje niestandardową logikę walidacji. Wynik programu obsługi aktualizuje ValidationMessageStore wystąpienie.
Podstawowa weryfikacja formularza jest przydatna w przypadkach, gdy model formularza jest zdefiniowany w składniku hostujący formularz, jako elementy członkowskie bezpośrednio w składniku lub w podklasie. Zaleca się użycie składnika modułu sprawdzania poprawności, w którym jest używana niezależna klasa modelu w kilku składnikach.
W Blazor Web Appprogramie s weryfikacja po stronie klienta wymaga aktywnego BlazorSignalR obwodu. Walidacja po stronie klienta nie jest dostępna dla formularzy w składnikach, które przyjęły statyczne renderowanie po stronie serwera (statyczne SSR). Formularze, które przyjmują statyczne SSR, są weryfikowane na serwerze po przesłaniu formularza.
W poniższym składniku HandleValidationRequested
metoda obsługi czyści wszelkie istniejące komunikaty sprawdzania poprawności przez wywołanie ValidationMessageStore.Clear metody sprawdzania poprawności formularza.
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;
}
}
}
Składnik modułu sprawdzania poprawności adnotacji danych i walidacja niestandardowa
Składnik DataAnnotationsValidator dołącza walidację adnotacji danych do kaskadowego EditContextelementu . Włączenie walidacji adnotacji danych wymaga DataAnnotationsValidator składnika. Aby użyć innego systemu weryfikacji niż adnotacje danych, użyj niestandardowej implementacji zamiast DataAnnotationsValidator składnika. Implementacje struktury dla programu DataAnnotationsValidator są dostępne do inspekcji w źródle referencyjnym:
Uwaga
Linki dokumentacji do źródła referencyjnego platformy .NET zwykle ładują domyślną gałąź repozytorium, która odzwierciedla bieżące programowanie dla następnej wersji platformy .NET. Aby wybrać tag dla określonej wersji, użyj listy rozwijanej Przełącz gałęzie lub tagi. Aby uzyskać więcej informacji, zobacz Jak wybrać tag wersji kodu źródłowego platformy ASP.NET Core (dotnet/AspNetCore.Docs #26205).
Blazor wykonuje dwa typy weryfikacji:
- Walidacja pola jest wykonywana, gdy użytkownik wyjmuje z pola. Podczas walidacji DataAnnotationsValidator pola składnik kojarzy wszystkie zgłoszone wyniki walidacji z polem.
- Walidacja modelu jest wykonywana po przesłaniu formularza przez użytkownika. Podczas walidacji DataAnnotationsValidator modelu składnik próbuje określić pole na podstawie nazwy elementu członkowskiego, którą raportuje wynik weryfikacji. Wyniki weryfikacji, które nie są skojarzone z pojedynczym elementem członkowskim, są skojarzone z modelem, a nie z polem.
Składniki modułu sprawdzania poprawności
Składniki modułu sprawdzania poprawności obsługują walidację formularza, zarządzając elementem ValidationMessageStore dla formularza EditContext.
Platforma Blazor udostępnia DataAnnotationsValidator składnik do dołączania obsługi walidacji do formularzy na podstawie atrybutów weryfikacji (adnotacji danych). Możesz utworzyć niestandardowe składniki modułu sprawdzania poprawności w celu przetwarzania komunikatów weryfikacji dla różnych formularzy na tej samej stronie lub w tym samym formularzu w różnych krokach przetwarzania formularzy (na przykład weryfikacji klienta, a następnie weryfikacji serwera). Przykładowy składnik modułu sprawdzania poprawności przedstawiony w tej sekcji CustomValidation
, jest używany w następujących sekcjach tego artykułu:
- Walidacja logiki biznesowej ze składnikiem modułu sprawdzania poprawności
- Walidacja serwera ze składnikiem modułu sprawdzania poprawności
Wbudowane moduły sprawdzania poprawności adnotacji danych nie są obsługiwane tylko [Remote]
w atrybucie walidacji.Blazor
Uwaga
Niestandardowe atrybuty weryfikacji adnotacji danych mogą być używane zamiast niestandardowych składników modułu sprawdzania poprawności w wielu przypadkach. Atrybuty niestandardowe zastosowane do modelu formularza aktywowane przy użyciu DataAnnotationsValidator składnika. W przypadku użycia z walidacją serwera wszystkie atrybuty niestandardowe zastosowane do modelu muszą być wykonywalne na serwerze. Aby uzyskać więcej informacji, zobacz sekcję Niestandardowe atrybuty walidacji.
Utwórz składnik modułu sprawdzania poprawności na podstawie elementu ComponentBase:
- EditContext Formularz jest parametrem kaskadowym składnika.
- Po zainicjowaniu składnika modułu sprawdzania poprawności zostanie utworzony nowy ValidationMessageStore element w celu zachowania bieżącej listy błędów formularza.
- Magazyn komunikatów odbiera błędy, gdy kod dewelopera w składniku formularza wywołuje metodę
DisplayErrors
. Błędy są przekazywane doDisplayErrors
metody w obiekcieDictionary<string, List<string>>
. W słowniku kluczem jest nazwa pola formularza, które zawiera co najmniej jeden błąd. Wartość to lista błędów. - Komunikaty są czyszczone po wystąpieniu któregokolwiek z następujących elementów:
- Żądanie weryfikacji jest wymagane w EditContext momencie zgłoszenia OnValidationRequested zdarzenia. Wszystkie błędy są czyszczone.
- Pole zmienia się w formularzu po wystąpieniu OnFieldChanged zdarzenia. Tylko błędy dla pola są czyszczone.
- Metoda jest wywoływana
ClearErrors
przez kod dewelopera. Wszystkie błędy są czyszczone.
Zaktualizuj przestrzeń nazw w poniższej klasie, aby odpowiadała przestrzeni nazw aplikacji.
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();
}
}
Ważne
Określenie przestrzeni nazw jest wymagane podczas wyprowadzania z ComponentBase. Nie można określić przestrzeni nazw powoduje błąd kompilacji:
Tag helpers cannot target tag name '<global namespace>.{CLASS NAME}' because it contains a ' ' character.
Symbol {CLASS NAME}
zastępczy to nazwa klasy składnika. Przykład niestandardowego modułu sprawdzania poprawności w tej sekcji określa przykładową przestrzeń nazw BlazorSample
.
Uwaga
Anonimowe wyrażenia lambda są zarejestrowanymi procedurami obsługi zdarzeń dla OnValidationRequested i OnFieldChanged w poprzednim przykładzie. Nie jest konieczne zaimplementowanie IDisposable i anulowanie subskrypcji delegatów zdarzeń w tym scenariuszu. Aby uzyskać więcej informacji, zobacz Cykl życia składników platformy ASP.NET Core Razor.
Walidacja logiki biznesowej ze składnikiem modułu sprawdzania poprawności
W przypadku ogólnej weryfikacji logiki biznesowej należy użyć składnika modułu sprawdzania poprawności, który odbiera błędy formularzy w słowniku.
Podstawowa walidacja jest przydatna w przypadkach, gdy model formularza jest zdefiniowany w składniku hostujący formularz, jako elementy członkowskie bezpośrednio w składniku lub w podklasie. Zaleca się użycie składnika modułu sprawdzania poprawności, w którym jest używana niezależna klasa modelu w kilku składnikach.
W poniższym przykładzie:
- Użyto skróconej
Starfleet Starship Database
wersji formularza (Starship3
składnika) sekcji Przykładowy formularz artykułu Składniki wejściowe, które akceptują tylko klasyfikację i opis starship. Walidacja adnotacji danych nie jest wyzwalana podczas przesyłania formularza, ponieważ DataAnnotationsValidator składnik nie jest uwzględniony w formularzu. - Używany
CustomValidation
jest składnik z sekcji Składniki modułu sprawdzania poprawności tego artykułu. - Walidacja wymaga wartości opisu statku (
Description
), jeśli użytkownik wybierze klasyfikację wysyłki "Defense
" (Classification
).
Po ustawieniu komunikatów sprawdzania poprawności w składniku są one dodawane do modułów sprawdzania poprawności ValidationMessageStore i wyświetlane w podsumowaniu EditFormweryfikacji.
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");
}
}
}
Uwaga
Zamiast używania składników weryfikacji można użyć atrybutów weryfikacji adnotacji danych. Atrybuty niestandardowe zastosowane do modelu formularza aktywowane przy użyciu DataAnnotationsValidator składnika. W przypadku użycia z walidacją serwera atrybuty muszą być wykonywalne na serwerze. Aby uzyskać więcej informacji, zobacz sekcję Niestandardowe atrybuty walidacji.
Walidacja serwera ze składnikiem modułu sprawdzania poprawności
Ta sekcja koncentruje się na Blazor Web App scenariuszach, ale podejście do dowolnej aplikacji korzystającej z weryfikacji serwera za pomocą internetowego interfejsu API przyjmuje takie samo ogólne podejście.
Ta sekcja koncentruje się na scenariuszach hostowanych Blazor WebAssembly , ale podejście dla dowolnego typu aplikacji korzystającej z weryfikacji serwera za pomocą internetowego interfejsu API przyjmuje takie samo ogólne podejście.
Walidacja serwera jest obsługiwana oprócz weryfikacji klienta:
- Przetwarzanie weryfikacji klienta w formularzu za DataAnnotationsValidator pomocą składnika.
- Gdy formularz przejdzie weryfikację klienta (OnValidSubmit jest wywoływany), wyślij element do interfejsu EditContext.Model API serwera zaplecza na potrzeby przetwarzania formularzy.
- Walidacja modelu przetwarzania na serwerze.
- Interfejs API serwera zawiera zarówno wbudowane adnotacje danych platformy, jak i niestandardową logikę walidacji dostarczaną przez dewelopera. Jeśli weryfikacja zakończy się pomyślnie na serwerze, przetwórz formularz i wyślij z powrotem kod stanu powodzenia (
200 - OK
). Jeśli walidacja nie powiedzie się, zwróć kod stanu błędu (400 - Bad Request
) i błędy walidacji pola. - Wyłącz formularz w przypadku powodzenia lub wyświetl błędy.
Podstawowa walidacja jest przydatna w przypadkach, gdy model formularza jest zdefiniowany w składniku hostujący formularz, jako elementy członkowskie bezpośrednio w składniku lub w podklasie. Zaleca się użycie składnika modułu sprawdzania poprawności, w którym jest używana niezależna klasa modelu w kilku składnikach.
Poniższy przykład jest oparty na:
- Element Blazor Web App z interaktywnymi składnikami zestawu WebAssembly utworzonymi na podstawie szablonu Blazor Web Appprojektu.
Starship
Model (Starship.cs
) sekcji Przykładowy formularz artykułu Składniki wejściowe.- Składnik
CustomValidation
pokazany w sekcji Składniki modułu sprawdzania poprawności.
Umieść model (Starship.cs
) w Starship
projekcie biblioteki klas udostępnionych, aby zarówno projekty klienta, jak i serwera mogły używać modelu. Dodaj lub zaktualizuj przestrzeń nazw, aby odpowiadała przestrzeni nazw udostępnionej aplikacji (na przykład namespace BlazorSample.Shared
). Ponieważ model wymaga adnotacji danych, upewnij się, że biblioteka klas udostępnionych używa struktury udostępnionej lub dodaj System.ComponentModel.Annotations
pakiet do udostępnionego projektu.
Uwaga
Aby uzyskać instrukcje dodawania pakietów do aplikacji .NET, zobacz artykuły w sekcji Instalowanie pakietów i zarządzanie nimi w temacie Przepływ pracy użycia pakietów (dokumentacja programu NuGet). Sprawdź prawidłowe wersje pakietów pod adresem NuGet.org.
W głównym projekcie programu Blazor Web Appdodaj kontroler w celu przetwarzania żądań weryfikacji starship i zwracania komunikatów weryfikacji, które zakończyły się niepowodzeniem. Zaktualizuj przestrzenie nazw w ostatniej using
instrukcji dla projektu biblioteki klas udostępnionych i namespace
dla klasy kontrolera. Oprócz weryfikacji adnotacji danych klienta i serwera kontroler sprawdza, czy wartość jest podana dla opisu statku (Description
), jeśli użytkownik wybierze klasyfikację Defense
wysyłki (Classification
).
- Blazor WebAssemblyHostowane rozwiązanie utworzone na podstawie szablonuBlazor WebAssembly projektu. Takie podejście jest obsługiwane w przypadku dowolnego z bezpiecznych rozwiązań hostowanych opisanych w dokumentacji dotyczącej hostowanych Blazor Blazor WebAssembly zabezpieczeń.
Starship
Model (Starship.cs
) sekcji Przykładowy formularz artykułu Składniki wejściowe.- Składnik
CustomValidation
pokazany w sekcji Składniki modułu sprawdzania poprawności.
Starship
Umieść model (Starship.cs
) w projekcie rozwiązaniaShared
, aby aplikacje klienckie i serwerowe mogły używać modelu. Dodaj lub zaktualizuj przestrzeń nazw, aby odpowiadała przestrzeni nazw udostępnionej aplikacji (na przykład namespace BlazorSample.Shared
). Ponieważ model wymaga adnotacji danych, dodaj System.ComponentModel.Annotations
pakiet do Shared
projektu.
Uwaga
Aby uzyskać instrukcje dodawania pakietów do aplikacji .NET, zobacz artykuły w sekcji Instalowanie pakietów i zarządzanie nimi w temacie Przepływ pracy użycia pakietów (dokumentacja programu NuGet). Sprawdź prawidłowe wersje pakietów pod adresem NuGet.org.
W projekcie Server dodaj kontroler do przetwarzania żądań weryfikacji starship i zwracania komunikatów weryfikacji, które zakończyły się niepowodzeniem. Zaktualizuj przestrzenie nazw w ostatniej using
instrukcji dla Shared
projektu i namespace
klasy kontrolera. Oprócz weryfikacji adnotacji danych klienta i serwera kontroler sprawdza, czy wartość jest podana dla opisu statku (Description
), jeśli użytkownik wybierze klasyfikację Defense
wysyłki (Classification
).
Walidacja Defense
klasyfikacji wysyłki odbywa się tylko na serwerze w kontrolerze, ponieważ zbliżający się formularz nie wykonuje tej samej weryfikacji po stronie klienta po przesłaniu formularza do serwera. Walidacja serwera bez walidacji klienta jest powszechna w aplikacjach, które wymagają prywatnej weryfikacji logiki biznesowej danych wejściowych użytkownika na serwerze. Na przykład informacje prywatne z danych przechowywanych dla użytkownika mogą być wymagane do zweryfikowania danych wejściowych użytkownika. Prywatne dane oczywiście nie mogą być wysyłane do klienta w celu weryfikacji klienta.
Uwaga
Kontroler StarshipValidation
w tej sekcji używa platformy Microsoft Identity 2.0. Internetowy interfejs API akceptuje tylko tokeny dla użytkowników, którzy mają zakres "API.Access
" dla tego interfejsu API. Dodatkowe dostosowanie jest wymagane, jeśli nazwa zakresu interfejsu API różni się od API.Access
.
Aby uzyskać więcej informacji na temat zabezpieczeń, zobacz:
- ASP.NET Core Blazor uwierzytelnianie i autoryzacja (oraz inne artykuły w temacie BlazorZabezpieczenia i Identity węzeł)
- Dokumentacja platformy Microsoft identity
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);
}
}
Potwierdź lub zaktualizuj przestrzeń nazw poprzedniego kontrolera (BlazorSample.Server.Controllers
), aby odpowiadała przestrzeni nazw kontrolerów aplikacji.
Gdy na serwerze wystąpi błąd weryfikacji powiązania modelu, ApiController
ApiControllerAttributezwykle zwraca domyślną nieprawidłową odpowiedź żądania z wartością ValidationProblemDetails. Odpowiedź zawiera więcej danych niż tylko błędy walidacji, jak pokazano w poniższym przykładzie, gdy wszystkie pola Starfleet Starship Database
formularza nie są przesyłane, a walidacja formularza kończy się niepowodzeniem:
{
"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)."]
}
}
Uwaga
Aby zademonstrować poprzednią odpowiedź JSON, należy wyłączyć weryfikację klienta formularza, aby zezwolić na przesyłanie pustego formularza pola lub użyć narzędzia do wysyłania żądania bezpośrednio do interfejsu API serwera, takiego jak Firefox Browser Developer.
Jeśli interfejs API serwera zwraca poprzednią domyślną odpowiedź JSON, klient może przeanalizować odpowiedź w kodzie dewelopera w celu uzyskania elementów podrzędnych węzła errors
na potrzeby przetwarzania błędów walidacji formularzy. Jest to niewygodne, aby napisać kod dewelopera, aby przeanalizować plik. Ręczne analizowanie kodu JSON wymaga utworzenia Dictionary<string, List<string>>
błędu po wywołaniu metody ReadFromJsonAsync. Najlepiej, aby interfejs API serwera zwracał tylko błędy weryfikacji, jak pokazano w poniższym przykładzie:
{
"Id": ["The Id field is required."],
"Classification": ["The Classification field is required."],
"IsValidatedDesign": ["This form disallows unapproved ships."],
"MaximumAccommodation": ["Accommodation invalid (1-100000)."]
}
Aby zmodyfikować odpowiedź interfejsu API serwera, aby zwracała tylko błędy walidacji, zmień delegata wywoływanego na akcje, które są oznaczone ApiControllerAttribute w Program
pliku. W przypadku punktu końcowego interfejsu API (/StarshipValidation
) zwróć element BadRequestObjectResult z wartością ModelStateDictionary. W przypadku innych punktów końcowych interfejsu API zachowaj domyślne zachowanie, zwracając wynik obiektu przy użyciu nowego ValidationProblemDetailselementu .
Microsoft.AspNetCore.Mvc Dodaj przestrzeń nazw na początku Program
pliku w głównym projekcie pliku :Blazor Web App
using Microsoft.AspNetCore.Mvc;
Program
W pliku dodaj lub zaktualizuj następującą AddControllersWithViews metodę rozszerzenia i dodaj następujące wywołanie do 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));
}
};
});
W przypadku dodawania kontrolerów do głównego projektu Blazor Web App po raz pierwszy punkty końcowe kontrolera mapy podczas umieszczania poprzedniego kodu, który rejestruje usługi dla kontrolerów. W poniższym przykładzie użyto domyślnych tras kontrolera:
app.MapDefaultControllerRoute();
Uwaga
Powyższy przykład jawnie rejestruje usługi kontrolera przez wywołanie metody AddControllersWithViews w celu automatycznego ograniczenia ataków między witrynami (XSRF/CSRF). Jeśli używasz tylko programu AddControllers, antyforgery nie jest włączana automatycznie.
Aby uzyskać więcej informacji na temat odpowiedzi błędów błędu routingu i walidacji kontrolera, zobacz następujące zasoby:
- Routing do akcji kontrolera na platformie ASP.NET Core
- Obsługa błędów w internetowych interfejsach API opartych na kontrolerze ASP.NET Core
W projekcie .Client
dodaj CustomValidation
składnik pokazany w sekcji Składniki modułu sprawdzania poprawności. Zaktualizuj przestrzeń nazw tak, namespace BlazorSample.Client
aby odpowiadała aplikacji (na przykład ).
W projekcie .Client
formularz jest aktualizowany w Starfleet Starship Database
celu wyświetlania błędów walidacji serwera z pomocą CustomValidation
składnika. Gdy interfejs API serwera zwraca komunikaty sprawdzania poprawności, są one dodawane do CustomValidation
składnika ValidationMessageStore. Błędy są dostępne w formularzu EditContext do wyświetlenia w podsumowaniu weryfikacji formularza.
W poniższym składniku zaktualizuj przestrzeń nazw udostępnionego projektu (@using BlazorSample.Shared
) do przestrzeni nazw udostępnionego projektu. Pamiętaj, że formularz wymaga autoryzacji, więc użytkownik musi być zalogowany do aplikacji, aby przejść do formularza.
Microsoft.AspNetCore.Mvc Dodaj przestrzeń nazw na początku Program
pliku w Server aplikacji:
using Microsoft.AspNetCore.Mvc;
Program
W pliku znajdź metodę AddControllersWithViews rozszerzenia i dodaj następujące wywołanie do ConfigureApiBehaviorOptionspliku :
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));
}
};
});
Uwaga
Powyższy przykład jawnie rejestruje usługi kontrolera przez wywołanie metody AddControllersWithViews w celu automatycznego ograniczenia ataków między witrynami (XSRF/CSRF). Jeśli używasz tylko programu AddControllers, antyforgery nie jest włączana automatycznie.
W projekcie Client dodaj CustomValidation
składnik pokazany w sekcji Składniki modułu sprawdzania poprawności. Zaktualizuj przestrzeń nazw tak, namespace BlazorSample.Client
aby odpowiadała aplikacji (na przykład ).
W projekcie Client formularz jest aktualizowany w Starfleet Starship Database
celu wyświetlania błędów walidacji serwera z pomocą CustomValidation
składnika. Gdy interfejs API serwera zwraca komunikaty sprawdzania poprawności, są one dodawane do CustomValidation
składnika ValidationMessageStore. Błędy są dostępne w formularzu EditContext do wyświetlenia w podsumowaniu weryfikacji formularza.
W poniższym składniku zaktualizuj przestrzeń nazw Shared
projektu (@using BlazorSample.Shared
) do przestrzeni nazw udostępnionego projektu. Pamiętaj, że formularz wymaga autoryzacji, więc użytkownik musi być zalogowany do aplikacji, aby przejść do formularza.
Starship10.razor
:
Uwaga
Formularze oparte na automatycznym EditForm włączaniu obsługi ochrony przed fałszerzami. Kontroler powinien używać AddControllersWithViews do rejestrowania usług kontrolera i automatycznego włączania obsługi ochrony przed fałszerstwa dla internetowego interfejsu 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
obiektu Blazor Web App musi również zarejestrować HttpClient żądania HTTP POST na kontrolerze internetowego interfejsu API zaplecza. Potwierdź lub dodaj następujący kod do .Client
pliku projektu Program
:
builder.Services.AddScoped(sp =>
new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
W poprzednim przykładzie ustawiono adres podstawowy (IWebAssemblyHostEnvironment.BaseAddress), który pobiera adres builder.HostEnvironment.BaseAddress
podstawowy dla aplikacji i jest zwykle pobierany z <base>
wartości tagu href
na stronie hosta.
@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.";
}
}
}
Uwaga
Zamiast używania składnika sprawdzania poprawności można użyć atrybutów weryfikacji adnotacji danych. Atrybuty niestandardowe zastosowane do modelu formularza aktywowane przy użyciu DataAnnotationsValidator składnika. W przypadku użycia z walidacją serwera atrybuty muszą być wykonywalne na serwerze. Aby uzyskać więcej informacji, zobacz sekcję Niestandardowe atrybuty walidacji.
Uwaga
Metoda sprawdzania poprawności serwera w tej sekcji jest odpowiednia dla dowolnego z przykładów hostowanych Blazor WebAssembly rozwiązań w tym zestawie dokumentacji:
InputText
na podstawie zdarzenia wejściowego
InputText Użyj składnika , aby utworzyć składnik niestandardowy, który używa oninput
zdarzenia (input
) zamiast onchange
zdarzenia (change
). Użycie walidacji pola wyzwalaczy zdarzeń na każdym naciśnięciu input
.
Poniższy CustomInputText
składnik dziedziczy składnik platformy InputText
i ustawia powiązanie zdarzeń na oninput
zdarzenie (input
).
CustomInputText.razor
:
@inherits InputText
<input @attributes="AdditionalAttributes"
class="@CssClass"
@bind="CurrentValueAsString"
@bind:event="oninput" />
Składnik CustomInputText
może być używany w dowolnym miejscu InputText . Poniższy składnik używa składnika udostępnionego CustomInputText
.
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; }
}
}
Składniki podsumowania weryfikacji i komunikatu weryfikacji
Składnik ValidationSummary zawiera podsumowanie wszystkich komunikatów sprawdzania poprawności, które są podobne do pomocnika tagu podsumowania weryfikacji:
<ValidationSummary />
Komunikaty sprawdzania poprawności danych wyjściowych dla określonego modelu z parametrem Model
:
<ValidationSummary Model="Model" />
Składnik ValidationMessage<TValue> wyświetla komunikaty sprawdzania poprawności dla określonego pola, które jest podobne do Pomocnika tagu komunikatu weryfikacji. Określ pole do weryfikacji za pomocą atrybutu For i wyrażenia lambda nazewnictwa właściwości modelu:
<ValidationMessage For="@(() => Model!.MaximumAccommodation)" />
Składniki ValidationMessage<TValue> i ValidationSummary obsługują dowolne atrybuty. Każdy atrybut, który nie jest zgodny z parametrem składnika, jest dodawany <div>
do wygenerowanego lub <ul>
elementu.
Kontrolowanie stylu komunikatów walidacji w arkuszu stylów aplikacji (wwwroot/css/app.css
lub wwwroot/css/site.css
). Domyślna validation-message
klasa ustawia kolor tekstu komunikatów walidacji na czerwony:
.validation-message {
color: red;
}
Ustal, czy pole formularza jest prawidłowe
Użyj EditContext.IsValid polecenia , aby określić, czy pole jest prawidłowe bez uzyskiwania komunikatów sprawdzania poprawności.
Obsługiwane, ale niezalecane:
var isValid = !editContext.GetValidationMessages(fieldIdentifier).Any();
Zalecane:
var isValid = editContext.IsValid(fieldIdentifier);
Niestandardowe atrybuty walidacji
Aby upewnić się, że wynik weryfikacji jest poprawnie skojarzony z polem podczas używania niestandardowego atrybutu weryfikacji, przekaż kontekst MemberName weryfikacji podczas tworzenia .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 });
}
}
Wstrzykiwanie usług do niestandardowych atrybutów walidacji za pomocą elementu ValidationContext. W poniższym przykładzie pokazano formularz szefa kuchni sałatki, który weryfikuje dane wejściowe użytkownika za pomocą wstrzykiwania zależności (DI).
Klasa SaladChef
wskazuje zatwierdzoną listę składników starship dla sałatki Ten Forward.
SaladChef.cs
:
namespace BlazorSample;
public class SaladChef
{
public string[] SaladToppers = { "Horva", "Kanda Root", "Krintar", "Plomeek",
"Syto Bean" };
}
Zarejestruj się SaladChef
w kontenerze DI aplikacji w Program
pliku:
builder.Services.AddTransient<SaladChef>();
Metoda IsValid
poniższej SaladChefValidatorAttribute
klasy uzyskuje usługę SaladChef
z di w celu sprawdzenia danych wejściowych użytkownika.
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));
}
}
Poniższy składnik weryfikuje dane wejściowe użytkownika, stosując SaladChefValidatorAttribute
element ([SaladChefValidator]
) do ciągu składnika sałatki (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);
}
Niestandardowe atrybuty klasy CSS walidacji
Niestandardowe atrybuty klasy CSS walidacji są przydatne podczas integrowania z platformami CSS, takimi jak Bootstrap.
Aby określić niestandardowe atrybuty klasy CSS walidacji, zacznij od udostępnienia stylów CSS na potrzeby walidacji niestandardowej. W poniższym przykładzie określono prawidłowe style (validField
) i nieprawidłowe (invalidField
).
Dodaj następujące klasy CSS do arkusza stylów aplikacji:
.validField {
border-color: lawngreen;
}
.invalidField {
background-color: tomato;
}
Utwórz klasę pochodną, FieldCssClassProvider która sprawdza komunikaty sprawdzania poprawności pól i stosuje odpowiedni prawidłowy lub nieprawidłowy 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";
}
}
Ustaw klasę jako dostawcę CustomFieldClassProvider
klas CSS pól w wystąpieniu formularza EditContext za pomocą polecenia 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; }
}
}
Powyższy przykład sprawdza ważność wszystkich pól formularza i stosuje styl do każdego pola. Jeśli formularz powinien stosować style niestandardowe tylko do podzestawu pól, zastosuj CustomFieldClassProvider
style warunkowo. CustomFieldClassProvider2
Poniższy przykład stosuje tylko styl do Name
pola. W przypadku wszystkich pól, które nie pasują do Name
nazwy , string.Empty
jest zwracany i nie zastosowano żadnego stylu. Przy użyciu odbicia pole jest dopasowywane do właściwości lub pola elementu członkowskiego modelu, a nie id
do jednostki 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;
}
}
Uwaga
Dopasowywanie nazwy pola w poprzednim przykładzie jest uwzględniane wielkości liter, więc element członkowski właściwości modelu oznaczony jako "Name
" musi być zgodny z sprawdzaniem warunkowym w elemencie "Name
":
- Poprawne dopasowanie:
fieldId.FieldName == "Name"
- Nie można dopasować:
fieldId.FieldName == "name"
- Nie można dopasować:
fieldId.FieldName == "NAME"
- Nie można dopasować:
fieldId.FieldName == "nAmE"
Dodaj dodatkową właściwość do Model
elementu , na przykład:
[StringLength(10, ErrorMessage = "Description is too long.")]
public string? Description { get; set; }
Dodaj element Description
do CustomValidationForm
formularza składnika:
<InputText @bind-Value="Model!.Description" />
EditContext Zaktualizuj wystąpienie w metodzie składnikaOnInitialized
, aby użyć nowego dostawcy klas CSS pól:
editContext?.SetFieldCssClassProvider(new CustomFieldClassProvider2());
Ponieważ klasa sprawdzania poprawności CSS nie jest stosowana do Description
pola, nie jest stylizowany. Jednak walidacja pola jest uruchamiana normalnie. Jeśli podano więcej niż 10 znaków, podsumowanie weryfikacji wskazuje błąd:
Opis jest za długi.
W poniższym przykładzie:
Niestandardowy styl CSS jest stosowany do
Name
pola.Wszystkie inne pola stosują logikę podobną do Blazordomyślnej logiki i używają Blazordomyślnych stylów walidacji CSS pól z
modified
valid
lubinvalid
. Pamiętaj, że w przypadku stylów domyślnych nie musisz dodawać ich do arkusza stylów aplikacji, jeśli aplikacja jest oparta na szablonie Blazor projektu. W przypadku aplikacji, które nie są oparte na szablonie Blazor projektu, do arkusza stylów aplikacji można dodać domyślne style:.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 Zaktualizuj wystąpienie w metodzie składnikaOnInitialized
, aby użyć poprzedniego dostawcy klas CSS pól:
editContext.SetFieldCssClassProvider(new CustomFieldClassProvider3());
Za pomocą polecenia CustomFieldClassProvider3
:
- Pole
Name
używa niestandardowych stylów CSS walidacji aplikacji. - Pole
Description
używa logiki podobnej do Blazorlogiki i Blazordomyślnych stylów walidacji CSS pól.
Walidacja na poziomie klasy za pomocą polecenia IValidatableObject
Walidacja IValidatableObject
na poziomie klasy (dokumentacja interfejsu API) jest obsługiwana w przypadku Blazor modeli formularzy. IValidatableObject Walidacja jest wykonywana tylko wtedy, gdy formularz zostanie przesłany i tylko wtedy, gdy wszystkie inne walidacje się powiedzie.
Blazor pakiet weryfikacji adnotacji danych
Jest Microsoft.AspNetCore.Components.DataAnnotations.Validation
to pakiet, który wypełnia luki w sprawdzaniu DataAnnotationsValidator poprawności przy użyciu składnika. Pakiet jest obecnie eksperymentalny.
Ostrzeżenie
Pakiet Microsoft.AspNetCore.Components.DataAnnotations.Validation
ma najnowszą wersję kandydata do wydania w NuGet.org. W tej chwili kontynuuj korzystanie z eksperymentalnego pakietu release candidate. Funkcje eksperymentalne są udostępniane w celu eksplorowania możliwości funkcji i mogą nie być dostarczane w stabilnej wersji. Zapoznaj się z repozytorium GitHub Anonss,dotnet/aspnetcore
repozytorium GitHub lub sekcją tego tematu, aby uzyskać dalsze aktualizacje.
Atrybut [CompareProperty]
Element CompareAttribute nie działa dobrze z składnikiem DataAnnotationsValidator , ponieważ DataAnnotationsValidator element nie kojarzy wyniku weryfikacji z określonym elementem członkowskim. Może to spowodować niespójne zachowanie między weryfikacją na poziomie pola a weryfikacją całego modelu w przesłaniu. Pakiet Microsoft.AspNetCore.Components.DataAnnotations.Validation
eksperymentalny wprowadza dodatkowy atrybut weryfikacji , ComparePropertyAttribute
który działa wokół tych ograniczeń. W aplikacji [CompareProperty]
jest bezpośrednim zamiennikiem atrybutu[Compare]
.Blazor
Zagnieżdżone modele, typy kolekcji i typy złożone
Blazor Zapewnia obsługę walidacji danych wejściowych formularza przy użyciu adnotacji danych z wbudowanym elementem DataAnnotationsValidator. Jednak DataAnnotationsValidator tylko weryfikuje właściwości najwyższego poziomu modelu powiązane z formularzem, które nie są właściwościami kolekcji ani typu złożonego.
Aby sprawdzić poprawność całego grafu obiektów powiązanego modelu, w tym właściwości kolekcji i typu złożonego, użyj ObjectGraphDataAnnotationsValidator
elementu dostarczonego przez pakiet eksperymentalnyMicrosoft.AspNetCore.Components.DataAnnotations.Validation
:
<EditForm ...>
<ObjectGraphDataAnnotationsValidator />
...
</EditForm>
Dodawanie adnotacji do właściwości modelu za pomocą polecenia [ValidateComplexType]
. W następujących klasach ShipDescription
modelu klasa zawiera dodatkowe adnotacje danych w celu zweryfikowania, kiedy model jest powiązany z formularzem:
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; }
}
Włączanie przycisku przesyłania na podstawie weryfikacji formularza
Aby włączyć i wyłączyć przycisk przesyłania na podstawie weryfikacji formularza, w poniższym przykładzie:
- Używa skróconej wersji wcześniejszego
Starfleet Starship Database
formularza (Starship3
składnika) sekcji Przykładowy formularz artykułu Składniki wejściowe, które akceptują tylko wartość identyfikatora wysyłki. InneStarship
właściwości otrzymują prawidłowe wartości domyślne po utworzeniuStarship
wystąpienia typu. - Używa formularza EditContext do przypisania modelu podczas inicjowania składnika.
- Weryfikuje formularz w wywołaniu zwrotnym kontekstu OnFieldChanged , aby włączyć i wyłączyć przycisk przesyłania.
- Implementuje IDisposable i anuluje subskrypcję programu obsługi zdarzeń w metodzie
Dispose
. Aby uzyskać więcej informacji, zobacz Cykl życia składników platformy ASP.NET Core Razor.
Uwaga
Podczas przypisywania do elementu EditForm.EditContextnie należy również przypisywać elementu EditForm.Model do elementu EditForm.
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;
}
}
}
Jeśli formularz nie jest wstępnie załadowany z prawidłowymi wartościami i chcesz wyłączyć Submit
przycisk podczas ładowania formularza, ustaw wartość formInvalid
true
.
Efektem ubocznym powyższego podejścia jest to, że podsumowanie weryfikacji (ValidationSummary składnik) jest wypełniane nieprawidłowymi polami po interakcji użytkownika z dowolnym polem. Rozwiąż ten scenariusz na jeden z następujących sposobów:
- Nie używaj ValidationSummary składnika w formularzu.
- Ustaw składnik jako widoczny po wybraniu ValidationSummary przycisku przesyłania (na przykład w metodzie
Submit
).
<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";
}
}