Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Notitie
Dit is niet de nieuwste versie van dit artikel. Zie de .NET 10-versie van dit artikel voor de huidige release.
Waarschuwing
Deze versie van ASP.NET Core wordt niet meer ondersteund. Zie de .NET- en .NET Core-ondersteuningsbeleidvoor meer informatie. Zie de .NET 9-versie van dit artikelvoor de huidige release.
In dit artikel wordt uitgelegd hoe u validatie gebruikt in Blazor formulieren.
Formuliervalidatie
In eenvoudige scenario's voor formuliervalidatie kan een EditForm exemplaar gedeclareerde EditContext en ValidationMessageStore instanties gebruiken om formuliervelden te valideren. Een handler voor de OnValidationRequested gebeurtenis van de EditContext voert aangepaste validatielogica uit. Het resultaat van de handler werkt de ValidationMessageStore instantie bij.
Basisformuliervalidatie is handig in gevallen waarin het model van het formulier wordt gedefinieerd in het onderdeel dat als host fungeert voor het formulier, hetzij als leden rechtstreeks in het onderdeel of in een subklasse. Het gebruik van een validatoronderdeel wordt aanbevolen wanneer een onafhankelijke modelklasse wordt gebruikt in verschillende onderdelen.
In Blazor Web Appis voor validatie aan de clientzijde een actief BlazorSignalR circuit vereist. Validatie aan de clientzijde is niet beschikbaar voor formulieren in onderdelen die statische rendering op de server hebben aangenomen (statische SSR). Formulieren die statische SSR aannemen, worden gevalideerd op de server nadat het formulier is verzonden.
In het volgende component wist de HandleValidationRequested-handlermethode eventuele bestaande validatieberichten door ValidationMessageStore.Clear aan te roepen, alvorens het formulier te valideren.
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;
}
}
}
Validatiecomponent voor Data Annotations en aangepaste validatie
Het DataAnnotationsValidator-onderdeel koppelt gegevensannotatie-validatie aan een cascade van EditContext. Voor het inschakelen van data-annotaties is het DataAnnotationsValidator component vereist. Als u een ander validatiesysteem wilt gebruiken dan gegevensaantekeningen, gebruikt u een aangepaste implementatie in plaats van het DataAnnotationsValidator-onderdeel. De framework-implementaties voor DataAnnotationsValidator zijn beschikbaar voor inspectie in de referentiebron:
Zie de DataAnnotationsValidator sectie validatiegedrag voor meer informatie over het validatiegedrag.
Als u ondersteuning voor validatie van gegevensaantekeningen voor een EditContext in code wilt inschakelen, roept u EnableDataAnnotationsValidation aan met een geïnjecteerde IServiceProvider (@inject IServiceProvider ServiceProvider) op de EditContext. Zie het NotifyPropertyChangedValidationComponent-onderdeel in de ASP.NET Core Blazor Framework-BasicTestApp (dotnet/aspnetcore GitHub-opslagplaats) voor een geavanceerd voorbeeld. Vervang in een productieversie van het voorbeeld het argument new TestServiceProvider() voor de serviceprovider door een geïnjecteerde IServiceProvider.
Notitie
Documentatiekoppelingen naar .NET-referentiebron laden meestal de standaardbranch van de opslagplaats, die de huidige ontwikkeling vertegenwoordigt voor de volgende release van .NET. Als u een tag voor een specifieke release wilt selecteren, gebruikt u de Switch-vertakkingen of tags vervolgkeuzelijst. Zie Een versietag selecteren van ASP.NET Core-broncode (dotnet/AspNetCore.Docs #26205)voor meer informatie.
Blazor voert twee typen validatie uit:
- Veldvalidatie wordt uitgevoerd zodra de gebruiker uit een veld tabt. Tijdens veldvalidatie koppelt het DataAnnotationsValidator onderdeel alle gerapporteerde validatieresultaten aan het veld.
- modelvalidatie wordt uitgevoerd wanneer de gebruiker het formulier indient. Tijdens modelvalidatie probeert het DataAnnotationsValidator onderdeel het veld te bepalen op basis van de lidnaam die door het validatieresultaat wordt gerapporteerd. Validatieresultaten die niet aan een afzonderlijk lid zijn gekoppeld, zijn gekoppeld aan het model in plaats van een veld.
In aangepaste validatiescenario's:
- Validatie beheert een ValidationMessageStore voor de EditContextvan een formulier.
- Het DataAnnotationsValidator-onderdeel wordt gebruikt voor het koppelen van validatieondersteuning aan formulieren op basis van validatiekenmerken (gegevensaantekeningen).
Er zijn twee algemene benaderingen voor het bereiken van aangepaste validatie, die worden beschreven in de volgende twee secties van dit artikel:
-
Handmatige validatie met behulp van de
OnValidationRequestedgebeurtenis: de velden van een formulier handmatig valideren met validatie van gegevensaantekeningen en aangepaste code voor veldcontroles wanneer validatie wordt aangevraagd via een gebeurtenishandler die is toegewezen aan de OnValidationRequested gebeurtenis. - Validator-onderdelen: een of meer aangepaste validatieonderdelen kunnen worden gebruikt voor het verwerken van validatie voor verschillende formulieren op dezelfde pagina of hetzelfde formulier in verschillende stappen van formulierverwerking (bijvoorbeeld clientvalidatie gevolgd door servervalidatie).
Handmatige validatie met behulp van de OnValidationRequested-gebeurtenis
U kunt een formulier handmatig valideren met een aangepaste gebeurtenishandler die is toegewezen aan de EditContext.OnValidationRequested gebeurtenis om een ValidationMessageStorete beheren.
Het Blazor framework biedt het DataAnnotationsValidator onderdeel om aanvullende validatieondersteuning toe te voegen aan formulieren op basis van validatiekenmerken (gegevensaantekeningen).
Zoals eerder Starship8 onderdeelvoorbeeld, wordt de HandleValidationRequested methode toegewezen aan OnValidationRequested, waar u handmatige validatie kunt uitvoeren in C#-code. Enkele wijzigingen laten zien hoe u de bestaande handmatige validatie combineert met validatie van gegevensaantekeningen via een DataAnnotationsValidator en een validatiekenmerk dat is toegepast op het Holodeck model.
Verwijs naar de System.ComponentModel.DataAnnotations namespace in de Razor richtlijnen van de component bovenaan het definitiebestand van de component.
@using System.ComponentModel.DataAnnotations
Voeg een eigenschap Id toe aan het Holodeck-model met een validatiekenmerk om de lengte van de tekenreeks te beperken tot zes tekens:
[StringLength(6)]
public string? Id { get; set; }
Voeg een DataAnnotationsValidator-onderdeel (<DataAnnotationsValidator />) toe aan het formulier. Normaal gesproken wordt het onderdeel direct onder de <EditForm> tag geplaatst, maar u kunt het overal in de vorm plaatsen:
<DataAnnotationsValidator />
Wijzig het verzendgedrag van het formulier in de <EditForm>-tag van OnSubmit in OnValidSubmit. Dit zorgt ervoor dat het formulier geldig is voordat de toegewezen gebeurtenishandlermethode wordt uitgevoerd:
- OnSubmit="Submit"
+ OnValidSubmit="Submit"
Voeg in de <EditForm>een veld toe voor de eigenschap Id:
<div>
<label>
<InputText @bind-Value="Model!.Id" />
ID (6 characters max)
</label>
<ValidationMessage For="() => Model!.Id" />
</div>
Nadat u de voorgaande wijzigingen hebt aangebracht, komt het gedrag van het formulier overeen met de volgende specificatie:
- De validatie van gegevensaantekeningen op de eigenschap
Idactiveert geen validatiefout wanneer hetIdveld slechts de focus verliest. De validatie wordt uitgevoerd wanneer de gebruiker de knopUpdateselecteert. - Handmatige validatie die u wilt uitvoeren in de
HandleValidationRequestedmethode die is toegewezen aan de OnValidationRequested gebeurtenis van het formulier wordt uitgevoerd wanneer de gebruiker de knopUpdatevan het formulier selecteert. In de bestaande code van het voorbeeld van hetStarship8-onderdeel moet de gebruiker een of beide selectievakjes inschakelen om het formulier te valideren. - Het formulier verwerkt de
Submitmethode pas nadat de gegevensaantekeningen en de handmatige validatie zijn geslaagd.
Validatieonderdelen
Validator-onderdelen ondersteunen formuliervalidatie door een ValidationMessageStore te beheren voor de EditContextvan een formulier.
Het Blazor framework biedt het DataAnnotationsValidator onderdeel voor het koppelen van validatieondersteuning aan formulieren op basis van validatiekenmerken (gegevensaantekeningen). U kunt aangepaste validatieonderdelen maken voor het verwerken van validatieberichten voor verschillende formulieren op dezelfde pagina of hetzelfde formulier in verschillende stappen voor formulierverwerking (bijvoorbeeld clientvalidatie gevolgd door servervalidatie). Het voorbeeld van het validatieonderdeel dat wordt weergegeven in deze sectie, CustomValidation, wordt gebruikt in de volgende secties van dit artikel:
Van de ingebouwde data-annotatieis alleen het [Remote] validatiekenmerk niet ondersteund in Blazor.
Notitie
Validatiekenmerken voor aangepaste gegevensaantekeningen kunnen in veel gevallen worden gebruikt in plaats van aangepaste validatieonderdelen. Aangepaste kenmerken die zijn toegepast op het model van het formulier worden geactiveerd met behulp van het DataAnnotationsValidator-onderdeel. Bij gebruik met servervalidatie moeten alle aangepaste kenmerken die op het model worden toegepast, uitvoerbaar zijn op de server. Zie de sectie Aangepaste validatiekenmerken voor meer informatie.
Een validatieonderdeel maken op basis van ComponentBase:
- De EditContext van het formulier is een trapsgewijze parameter van het onderdeel.
- Wanneer het validatieonderdeel wordt geïnitialiseerd, wordt er een nieuwe ValidationMessageStore gemaakt om een huidige lijst met formulierfouten te onderhouden.
- Het berichtenarchief ontvangt fouten wanneer ontwikkelaarscode in het onderdeel van het formulier de
DisplayErrorsmethode aanroept. De fouten worden doorgegeven aan deDisplayErrorsmethode in eenDictionary<string, List<string>>. In de woordenlijst is de sleutel de naam van het formulierveld met een of meer fouten. De waarde is de lijst met fouten. - Berichten worden gewist wanneer zich een van de volgende situaties voordoet:
- Validatie wordt aangevraagd op de EditContext wanneer de OnValidationRequested gebeurtenis wordt gegenereerd. Alle fouten worden gewist.
- Er wordt een veld in het formulier gewijzigd wanneer de gebeurtenis OnFieldChanged wordt gegenereerd. Alleen de fouten voor het veld worden gewist.
- De methode
ClearErrorswordt aangeroepen door ontwikkelaarscode. Alle fouten worden gewist.
Werk de naamruimte in de volgende klasse bij zodat deze overeenkomt met de naamruimte van uw app.
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();
}
}
Belangrijk
Het specificeren van een naamruimte is vereist wanneer er wordt afgeleid van ComponentBase. Als er geen naamruimte wordt opgegeven, leidt dat tot een buildfout:
Tag helpers cannot target tag name '<global namespace>.{CLASS NAME}' because it contains a ' ' character.
De tijdelijke aanduiding {CLASS NAME} is de naam van de onderdeelklasse. In het aangepaste validatievoorbeeld in deze sectie wordt de voorbeeldnaamruimte BlazorSampleopgegeven.
Notitie
Anonieme lambda-expressies zijn geregistreerde gebeurtenis-handlers voor OnValidationRequested en OnFieldChanged in het vorige voorbeeld. Het is niet nodig om IDisposable te implementeren en de gedelegeerden voor gebeurtenissen in dit scenario af te melden. Zie ASP.NET Core Razor component verwijderingvoor meer informatie.
Validatie van bedrijfslogica met een validatieonderdeel
Voor algemene validatie van bedrijfslogica gebruikt u een validatoronderdeel dat formulierfouten in een woordenlijst ontvangt.
Basisvalidatie is handig in gevallen waarin het model van het formulier wordt gedefinieerd in het onderdeel dat als host fungeert voor het formulier, hetzij als leden rechtstreeks in het onderdeel of in een subklasse. Het gebruik van een validatieonderdeel wordt aanbevolen wanneer een onafhankelijke modelklasse wordt gebruikt voor verschillende onderdelen.
In het volgende voorbeeld:
- Een verkorte versie van het
Starfleet Starship Databaseformulier (Starship3onderdeel) van het voorbeeldformulier sectie van de invoeronderdelen artikel wordt gebruikt dat alleen de classificatie en beschrijving van het sterschip accepteert. Validatie van gegevensaantekening wordt niet geactiveerd bij het indienen van formulieren omdat het DataAnnotationsValidator onderdeel niet is opgenomen in het formulier. - Het
CustomValidationonderdeel van de Validator-onderdelen sectie van dit artikel wordt gebruikt. - Voor de validatie is een waarde vereist voor de beschrijving van het schip (
Description) als de gebruiker de "Defense" verzendclassificatie (Classification) selecteert.
Wanneer validatieberichten zijn ingesteld in het onderdeel, worden ze toegevoegd aan de ValidationMessageStore van de validator en weergegeven in het validatieoverzicht van de EditForm.
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),
[ "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),
[ "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");
}
}
}
Notitie
Als alternatief voor het gebruik van validatieonderdelenkunnen validatiekenmerken voor gegevensaantekeningen worden gebruikt. Aangepaste kenmerken die zijn toegepast op het model van het formulier worden geactiveerd met behulp van het DataAnnotationsValidator-onderdeel. Bij gebruik met servervalidatie moeten de kenmerken uitvoerbaar zijn op de server. Zie de sectie Aangepaste validatiekenmerken voor meer informatie.
Servervalidatie met een validatieonderdeel
Deze sectie is gericht op Blazor Web App scenario's, maar de benadering voor elk type app dat gebruikmaakt van servervalidatie met web-API, heeft dezelfde algemene benadering.
Deze sectie is gericht op gehoste Blazor WebAssembly scenario's, maar de benadering voor elk type app dat gebruikmaakt van servervalidatie met web-API, heeft dezelfde algemene benadering.
Servervalidatie wordt ondersteund naast clientvalidatie:
- Voer de clientvalidatie uit in het formulier met de DataAnnotationsValidator-component.
- Wanneer het formulier clientvalidatie doorgeeft (OnValidSubmit wordt aangeroepen), verzendt u de EditContext.Model naar een API van de back-endserver voor formulierverwerking.
- Procesmodelvalidatie op de server.
- De server-API bevat zowel de ingebouwde frameworkgegevensvalidatie als aangepaste validatielogica die door de ontwikkelaar wordt geleverd. Als de validatie wordt doorgegeven aan de server, verwerkt u het formulier en stuurt u een geslaagde statuscode (
200 - OK). Als de validatie mislukt, retourneert u een foutcode (400 - Bad Request) en de veldvalidatiefouten. - Schakel het formulier uit bij succes of geef de fouten weer.
Basisvalidatie is handig in gevallen waarin het model van het formulier wordt gedefinieerd in het onderdeel dat als host fungeert voor het formulier, hetzij als leden rechtstreeks in het onderdeel of in een subklasse. Het gebruik van een validatieonderdeel wordt aanbevolen wanneer een onafhankelijke modelklasse wordt gebruikt voor verschillende onderdelen.
Het volgende voorbeeld is gebaseerd op:
- Een Blazor Web App met interactieve WebAssembly-onderdelen die zijn gemaakt op basis van de Blazor Web App projectsjabloon.
- Het
Starshipmodel (Starship.cs) van het voorbeeldformulier sectie van de invoeronderdelen artikel. - Het
CustomValidation-onderdeel wordt weergegeven in de sectie -validatoronderdelen.
Plaats het Starship model (Starship.cs) in een gedeeld klassebibliotheekproject, zodat zowel de client- als serverprojecten het model kunnen gebruiken. Voeg de naamruimte toe of werk deze bij zodat deze overeenkomt met de naamruimte van de gedeelde app (bijvoorbeeld namespace BlazorSample.Shared). Omdat voor het model gegevensaantekeningen zijn vereist, controleert u of de gedeelde klassebibliotheek gebruikmaakt van het gedeelde framework of het System.ComponentModel.Annotations-pakket toevoegt aan het gedeelde project.
Notitie
Zie de artikelen onder Pakketten installeren en beheren bij Pakketverbruikworkflow (NuGet-documentatie)voor hulp bij het toevoegen van pakketten aan .NET-apps. Bevestig de juiste pakketversies op NuGet.org.
Voeg in het hoofdproject van de Blazor Web Appeen controller toe om sterschipvalidatieaanvragen te verwerken en mislukte validatieberichten te retourneren. Werk de naamruimten in de laatste using-instructie voor het gedeelde klassebibliotheekproject en de namespace voor de controllerklasse bij. Naast validatie van client- en servergegevens valideert de controller dat er een waarde is opgegeven voor de beschrijving van het schip (Description) als de gebruiker de Defense scheepsclassificatie (Classification) selecteert.
- Een gehoste Blazor WebAssembly-oplossing gemaakt op basis van de Blazor WebAssembly projectsjabloon. De aanpak wordt ondersteund voor een van de beveiligde gehoste Blazor-oplossingen die worden beschreven in de gehoste Blazor WebAssembly beveiligingsdocumentatie.
- Het
Starshipmodel (Starship.cs) van het voorbeeldformulier sectie van de invoeronderdelen artikel. - Het
CustomValidation-onderdeel wordt weergegeven in de sectie -validatoronderdelen.
Plaats het Starship model (Starship.cs) in het Shared project van de oplossing, zodat zowel de client- als server-apps het model kunnen gebruiken. Voeg de naamruimte toe of werk deze bij zodat deze overeenkomt met de naamruimte van de gedeelde app (bijvoorbeeld namespace BlazorSample.Shared). Omdat voor het model gegevensaantekeningen zijn vereist, voegt u het System.ComponentModel.Annotations-pakket toe aan het Shared-project.
Notitie
Zie de artikelen onder Pakketten installeren en beheren bij Pakketverbruikworkflow (NuGet-documentatie)voor hulp bij het toevoegen van pakketten aan .NET-apps. Bevestig de juiste pakketversies op NuGet.org.
Voeg in het Server project een controller toe om sterschipvalidatieaanvragen te verwerken en mislukte validatieberichten te retourneren. Werk de naamruimten in de laatste using-instructie voor het Shared-project en de namespace voor de controllerklasse bij. Naast validatie van client- en servergegevens valideert de controller dat er een waarde is opgegeven voor de beschrijving van het schip (Description) als de gebruiker de Defense scheepsclassificatie (Classification) selecteert.
De validatie voor de Defense scheepsclassificatie vindt alleen plaats op de server in de controller, omdat het aanstaande formulier niet dezelfde validatie aan de clientzijde uitvoert wanneer het formulier naar de server wordt verzonden. Servervalidatie zonder clientvalidatie is gebruikelijk in apps waarvoor persoonlijke bedrijfslogicavalidatie van gebruikersinvoer op de server is vereist. Privégegevens van gegevens die zijn opgeslagen voor een gebruiker, kunnen bijvoorbeeld vereist zijn om gebruikersinvoer te valideren. Privégegevens kunnen uiteraard niet naar de client worden verzonden voor clientvalidatie.
Notitie
De StarshipValidation controller in deze sectie maakt gebruik van Microsoft Identity 2.0. De web-API accepteert alleen tokens voor gebruikers met het bereik 'API.Access' voor deze API. Aanvullende aanpassing is vereist als de bereiknaam van de API verschilt van API.Access.
Zie voor meer informatie over beveiliging:
- ASP.NET Core Blazor authenticatie en autorisatie (en de andere artikelen in het knooppunt BlazorBeveiliging en Identity)
- documentatie voor Microsoft Identity Platform
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 = [ "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);
}
}
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);
}
}
Bevestig of werk de naamruimte van de voorgaande controller (BlazorSample.Server.Controllers) bij zodat deze overeenkomt met de naamruimte van de controllers van de app.
Wanneer een validatiefout voor modelbinding optreedt op de server, retourneert een ApiController (ApiControllerAttribute) normaal gesproken een standaardantwoord voor ongeldige aanvragen met een ValidationProblemDetails. Het antwoord bevat meer gegevens dan alleen de validatiefouten, zoals wordt weergegeven in het volgende voorbeeld wanneer alle velden van het formulier Starfleet Starship Database niet worden verzonden en de validatie van het formulier mislukt:
{
"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)." ]
}
}
Notitie
Als u het voorgaande JSON-antwoord wilt demonstreren, moet u de clientvalidatie van het formulier uitschakelen om het indienen van lege velden toe te staan of een hulpprogramma gebruiken om een aanvraag rechtstreeks naar de server-API te verzenden, zoals Firefox Browser Developer-.
Als de server-API het voorgaande standaard-JSON-antwoord retourneert, kan de client het antwoord parseren in ontwikkelaarscode om de onderliggende elementen van het errors-knooppunt te verkrijgen voor het verwerken van formuliervalidatiefouten. Het is onhandig om code voor ontwikkelaars te schrijven om het bestand te parseren. Voor het handmatig parseren van de JSON moeten er Dictionary<string, List<string>> fouten worden gegenereerd nadat ReadFromJsonAsyncis aangeroepen. In het ideale geval moet de server-API alleen de validatiefouten retourneren, zoals in het volgende voorbeeld wordt weergegeven:
{
"Id": [ "The Id field is required." ],
"Classification": [ "The Classification field is required." ],
"IsValidatedDesign": [ "This form disallows unapproved ships." ],
"MaximumAccommodation": [ "Accommodation invalid (1-100000)." ]
}
Als u het antwoord van de server-API wilt wijzigen zodat deze alleen de validatiefouten retourneert, wijzigt u de gemachtigde die wordt aangeroepen voor acties die zijn geannoteerd met ApiControllerAttribute in het Program-bestand. Voor het API-eindpunt (/StarshipValidation) retourneert u een BadRequestObjectResult met de ModelStateDictionary. Voor andere API-eindpunten behoudt u het standaardgedrag door het objectresultaat te retourneren met een nieuwe ValidationProblemDetails.
Voeg de Microsoft.AspNetCore.Mvc-naamruimte toe aan de bovenkant van het Program-bestand in het hoofdproject van de Blazor Web App:
using Microsoft.AspNetCore.Mvc;
Voeg in het bestand Program de volgende AddControllersWithViews extensiemethode toe of werk deze bij en voeg de volgende aanroep toe aan 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));
}
};
});
Als u voor het eerst controllers toevoegt aan het hoofdproject van de Blazor Web App, wijs de eindpunten van controllers toe wanneer u de voorafgaande code plaatst die de services voor controllers registreert. In het volgende voorbeeld worden standaardcontrollerroutes gebruikt:
app.MapDefaultControllerRoute();
Notitie
In het voorgaande voorbeeld worden controllerservices expliciet geregistreerd door AddControllersWithViews aan te roepen om automatisch aanvallen op cross-siteaanvraagvervalsing (XSRF/CSRF) te beperken. Als u slechts AddControllersgebruikt, wordt antivervalsing niet automatisch ingeschakeld.
Zie de volgende bronnen voor meer informatie over foutreacties voor controllerroutering en validatiefouten:
Voeg in het .Client project het CustomValidation onderdeel toe dat wordt weergegeven in de sectie Validator-onderdelen. Werk de naamruimte bij zodat deze overeenkomt met de app (bijvoorbeeld namespace BlazorSample.Client).
In het .Client-project wordt het Starfleet Starship Database formulier bijgewerkt om servervalidatiefouten weer te geven met behulp van het CustomValidation-onderdeel. Wanneer de server-API validatieberichten retourneert, worden deze toegevoegd aan de CustomValidationvan het ValidationMessageStore onderdeel. De fouten zijn beschikbaar in formulier EditContext voor weergave in de validatiesamenvatting van het formulier.
Werk in het volgende onderdeel de naamruimte van het gedeelde project (@using BlazorSample.Shared) bij naar de naamruimte van het gedeelde project. Houd er rekening mee dat voor het formulier autorisatie is vereist, dus de gebruiker moet zijn aangemeld bij de app om naar het formulier te navigeren.
Voeg de Microsoft.AspNetCore.Mvc naamruimte boven aan het Program-bestand toe in de Server-app:
using Microsoft.AspNetCore.Mvc;
Zoek in het bestand Program de AddControllersWithViews-extensiemethode en voeg de volgende aanroep toe aan 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));
}
};
});
Notitie
In het voorgaande voorbeeld worden controllerservices expliciet geregistreerd door AddControllersWithViews aan te roepen om automatisch aanvallen op cross-siteaanvraagvervalsing (XSRF/CSRF) te beperken. Als u slechts AddControllersgebruikt, wordt antivervalsing niet automatisch ingeschakeld.
Voeg in het Client project het CustomValidation onderdeel toe dat wordt weergegeven in de sectie Validator-onderdelen. Werk de naamruimte bij zodat deze overeenkomt met de app (bijvoorbeeld namespace BlazorSample.Client).
In het Client-project wordt het Starfleet Starship Database formulier bijgewerkt om servervalidatiefouten weer te geven met behulp van het CustomValidation-onderdeel. Wanneer de server-API validatieberichten retourneert, worden deze toegevoegd aan de CustomValidationvan het ValidationMessageStore onderdeel. De fouten zijn beschikbaar in formulier EditContext voor weergave in de validatiesamenvatting van het formulier.
Werk in het volgende onderdeel de naamruimte van het Shared project (@using BlazorSample.Shared) bij naar de naamruimte van het gedeelde project. Houd er rekening mee dat voor het formulier autorisatie is vereist, dus de gebruiker moet zijn aangemeld bij de app om naar het formulier te navigeren.
Starship10.razor:
Notitie
Formulieren op basis van EditForm schakelen automatisch ondersteuning voor antivervalsing in. De controller moet AddControllersWithViews gebruiken om controllerservices te registreren en automatisch antiforgery-ondersteuning in te schakelen voor de web-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
{
using 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.";
}
}
}
Het .Client project van een Blazor Web App moet ook een HttpClient registreren voor HTTP POST-aanvragen naar een back-endweb-API-controller. Bevestig of voeg het volgende toe aan het .Client-bestand van het Program project:
builder.Services.AddScoped(sp =>
new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
In het voorgaande voorbeeld wordt het basisadres ingesteld met builder.HostEnvironment.BaseAddress (IWebAssemblyHostEnvironment.BaseAddress), waarmee het basisadres voor de app wordt opgehaald en doorgaans wordt afgeleid van de <base> waarde van de href tag op de hostpagina.
@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
{
using 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.";
}
}
}
Notitie
Als alternatief voor het gebruik van een validatieonderdeel, kunnen validatiekenmerken voor gegevensaantekening worden gebruikt. Aangepaste kenmerken die zijn toegepast op het model van het formulier worden geactiveerd met behulp van het DataAnnotationsValidator-onderdeel. Bij gebruik met servervalidatie moeten de kenmerken uitvoerbaar zijn op de server. Zie de sectie Aangepaste validatiekenmerken voor meer informatie.
Notitie
De servervalidatiemethode in deze sectie is geschikt voor een van de gehoste Blazor WebAssembly oplossingsvoorbeelden in deze documentatieset:
InputText op basis van de ingevoerde gebeurtenis
Gebruik het InputText-onderdeel om een aangepast onderdeel te maken dat gebruikmaakt van de oninput gebeurtenis (input) in plaats van de onchange gebeurtenis (change). Het gebruik van de input gebeurtenis activeert veldvalidatie op elke toetsaanslag.
Het volgende CustomInputText onderdeel neemt het InputText-onderdeel van het framework over en stelt gebeurtenisbinding in op de oninput gebeurtenis (input).
CustomInputText.razor:
@inherits InputText
<input @attributes="AdditionalAttributes"
class="@CssClass"
@bind="CurrentValueAsString"
@bind:event="oninput" />
Het CustomInputText-onderdeel kan overal worden gebruikt waar InputText wordt gebruikt. Het volgende onderdeel maakt gebruik van het gedeelde CustomInputText-onderdeel.
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; }
}
}
Onderdelen van validatiesamenvatting en validatiebericht
Het ValidationSummary-onderdeel bevat een overzicht van alle validatieberichten, die vergelijkbaar zijn met de Helper voor validatieoverzichtstags:
<ValidationSummary />
Uitvoervalidatieberichten voor een specifiek model met de parameter Model:
<ValidationSummary Model="Model" />
Het ValidationMessage<TValue>-onderdeel geeft validatieberichten weer voor een specifiek veld. Dit is vergelijkbaar met de Helper voor validatieberichttags. Geef het veld voor validatie op met het kenmerk For en een lambda-expressie met de naam van de modeleigenschap:
<ValidationMessage For="@(() => Model!.MaximumAccommodation)" />
De ValidationMessage<TValue>- en ValidationSummary-onderdelen ondersteunen willekeurige kenmerken. Een kenmerk dat niet overeenkomt met een onderdeelparameter, wordt toegevoegd aan het gegenereerde <div>- of <ul>-element.
De stijl van validatieberichten in het opmaakmodel van de app beheren (wwwroot/css/app.css of wwwroot/css/site.css). De standaardklasse validation-message stelt de tekstkleur van validatieberichten in op rood:
.validation-message {
color: red;
}
Bepalen of een formulierveld geldig is
Gebruik EditContext.IsValid om te bepalen of een veld geldig is zonder validatieberichten te verkrijgen.
ondersteund, maar niet aanbevolen:
var isValid = !editContext.GetValidationMessages(fieldIdentifier).Any();
✔️ aanbevolen:
var isValid = editContext.IsValid(fieldIdentifier);
Aangepaste validatiekenmerken
Om ervoor te zorgen dat het validatieresultaat correct is gekoppeld aan een veld wanneer u een aangepast validatiekenmerk gebruikt, geef dan de MemberName van de validatiecontext door bij het maken van het 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.",
[ validationContext.MemberName! ]);
}
}
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! });
}
}
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 });
}
}
Injecteer services in aangepaste validatiekenmerken via de ValidationContext. In het volgende voorbeeld ziet u een salade chef-formulier waarmee gebruikersinvoer wordt gevalideerd met afhankelijkheidsinjectie (DI).
De SaladChef-klasse geeft de goedgekeurde ingrediëntenlijst voor een Ten Forward-salade aan.
SaladChef.cs:
namespace BlazorSample;
public class SaladChef
{
public string[] SaladToppers = { "Horva", "Kanda Root", "Krintar", "Plomeek",
"Syto Bean" };
}
Registreer SaladChef in de DI-container van de app in het Program-bestand:
builder.Services.AddTransient<SaladChef>();
De IsValid methode van de volgende SaladChefValidatorAttribute klasse verkrijgt de SaladChef service van DI om de invoer van de gebruiker te controleren.
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));
}
}
Het volgende onderdeel valideert gebruikersinvoer door de SaladChefValidatorAttribute ([SaladChefValidator]) toe te passen op de tekenreeks voor salade-ingrediënten (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);
}
Aangepaste css-klassekenmerken voor validatie
Aangepaste css-klassekenmerken voor validatie zijn handig bij het integreren met CSS-frameworks, zoals Bootstrap-.
Als u aangepaste css-klassekenmerken voor validatie wilt opgeven, geeft u eerst CSS-stijlen voor aangepaste validatie op. In het volgende voorbeeld worden geldige stijlen (validField) en ongeldige stijlen (invalidField) opgegeven.
Voeg de volgende CSS-klassen toe aan het opmaakmodel van de app:
.validField {
border-color: lawngreen;
}
.invalidField {
background-color: tomato;
}
Maak een klasse die is afgeleid van FieldCssClassProvider die controleert op veldvalidatieberichten en de juiste geldige of ongeldige stijl toepast.
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";
}
}
Stel de CustomFieldClassProvider klasse in als veld-CSS-klasseprovider in het EditContext exemplaar van het formulier met 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; }
}
}
In het voorgaande voorbeeld wordt de geldigheid van alle formuliervelden gecontroleerd en wordt een stijl toegepast op elk veld. Als het formulier alleen aangepaste stijlen mag toepassen op een subset van de velden, moet CustomFieldClassProvider stijlen voorwaardelijk toepassen. In het volgende CustomFieldClassProvider2 voorbeeld wordt alleen een stijl toegepast op het Name veld. Voor velden met namen die niet overeenkomen met Name, wordt string.Empty geretourneerd en wordt er geen stijl toegepast. Met weerspiegelingwordt het veld afgestemd op de eigenschap of veldnaam van het modelonderdeel, niet een veld id toegewezen aan de HTML-entiteit.
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;
}
}
Notitie
Het overeenkomen met de veldnaam in het vorige voorbeeld is hoofdlettergevoelig, dus moet een modeleigenschapslid dat is aangeduid met 'Name' overeenkomen met een voorwaardelijke controle op 'Name'.
- ✔️ komt correct overeen:
fieldId.FieldName == "Name" -
komt niet overeen:
fieldId.FieldName == "name" -
komt niet overeen:
fieldId.FieldName == "NAME" -
komt niet overeen:
fieldId.FieldName == "nAmE"
Voeg een extra eigenschap toe aan Model, bijvoorbeeld:
[StringLength(10, ErrorMessage = "Description is too long.")]
public string? Description { get; set; }
Voeg de Description toe aan de vorm van de CustomValidationForm-component.
<InputText @bind-Value="Model!.Description" />
Werk het EditContext exemplaar bij in de OnInitialized methode van het onderdeel om de nieuwe CSS-klasseprovider voor velden te gebruiken:
editContext?.SetFieldCssClassProvider(new CustomFieldClassProvider2());
Omdat een CSS-validatieklasse niet wordt toegepast op het Description veld, wordt deze niet gestijld. Veldvalidatie wordt echter normaal uitgevoerd. Als er meer dan 10 tekens worden opgegeven, geeft de validatiesamenvatting de fout aan:
Beschrijving is te lang.
In het volgende voorbeeld:
De aangepaste CSS-stijl wordt toegepast op het
Nameveld.Alle andere velden passen logica toe die vergelijkbaar is met de standaardlogica van Blazoren het gebruik van de standaard css-validatiestijlen voor velden van Blazor,
modifiedmetvalidofinvalid. Houd er rekening mee dat u voor de standaardstijlen deze niet hoeft toe te voegen aan het opmaakmodel van de app als de app is gebaseerd op een Blazor projectsjabloon. Voor apps die niet zijn gebaseerd op een Blazor projectsjabloon, kunnen de standaardstijlen worden toegevoegd aan het opmaakmodel van de app:.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";
}
}
}
}
Werk het EditContext-exemplaar bij in de OnInitialized-methode van het onderdeel om de voorgaande Field CSS Class Provider te gebruiken.
editContext.SetFieldCssClassProvider(new CustomFieldClassProvider3());
Met behulp van CustomFieldClassProvider3:
- Het veld
Namemaakt gebruik van de aangepaste CSS-stijlen voor validatie van de app. - Het veld
Descriptionmaakt gebruik van logica die vergelijkbaar is met de logica van Blazoren Blazorstandaard css-validatiestijlen voor velden.
Validatie op klasseniveau met IValidatableObject
validatie op klasseniveau met IValidatableObject (API-documentatie) wordt ondersteund voor Blazor formuliermodellen.
IValidatableObject validatie wordt alleen uitgevoerd wanneer het formulier wordt verzonden en alleen als alle andere validaties zijn geslaagd.
validatiepakket voor Blazor gegevensaantekeningen
Notitie
Het Microsoft.AspNetCore.Components.DataAnnotations.Validation pakket wordt niet meer aanbevolen voor apps die gericht zijn op .NET 10 of hoger. Zie de sectie Geneste objecten, verzamelingstypen en complexe typen voor meer informatie.
Het Microsoft.AspNetCore.Components.DataAnnotations.Validation pakket vult de validatie-ervaring hiaten in met behulp van het DataAnnotationsValidator onderdeel. Het pakket is momenteel experimenteel.
Waarschuwing
Het Microsoft.AspNetCore.Components.DataAnnotations.Validation pakket heeft een nieuwste versie van de releasekandidaat op NuGet.org. Blijf op dit moment het experimentele release-kandidaatpakket gebruiken. Experimentele functies worden geboden voor het verkennen van de levensvatbaarheid van functies en worden mogelijk niet in een stabiele versie verzonden. Bekijk de GitHub-opslagplaats aankondigingen, de dotnet/aspnetcore GitHub-opslagplaatsof dit onderwerpsectie voor verdere updates.
kenmerk [CompareProperty]
De CompareAttribute werkt niet goed met het DataAnnotationsValidator onderdeel omdat de DataAnnotationsValidator het validatieresultaat niet koppelt aan een specifiek lid. Dit kan leiden tot inconsistent gedrag tussen validatie op veldniveau en wanneer het hele model op een submit wordt gevalideerd. Het Microsoft.AspNetCore.Components.DataAnnotations.Validationexperimentele pakket introduceert een extra validatiekenmerk, ComparePropertyAttributedat deze beperkingen omzeilt. In een Blazor-app is [CompareProperty] een directe vervanging voor het [Compare] kenmerk.
Geneste objecten en verzamelingstypen
Blazor Formuliervalidatie biedt ondersteuning voor het valideren van eigenschappen van geneste objecten en collectie-items met de ingebouwde DataAnnotationsValidator.
Als u een gevalideerd formulier wilt maken, gebruikt u een DataAnnotationsValidator onderdeel in een EditForm onderdeel, net als voorheen.
U kunt kiezen voor de validatiefunctie voor geneste objecten en verzamelingstypen:
- Roep de AddValidation extensiemethode aan in het
Programbestand waarin services zijn geregistreerd. - Declareer de formuliermodeltypen in een C#-klassebestand, niet in een Razor onderdeel (
.razor). - Annoteer het hoofdformuliermodeltype met de
[ValidatableType]eigenschap.
Zonder de voorgaande stappen te volgen, bevat formuliervalidatiegedrag geen geneste model- en verzamelingstypevalidatie.
In het volgende voorbeeld ziet u klantorders met de verbeterde formuliervalidatie (details weggelaten voor beknoptheid):
Roep Program.csin op AddValidation de serviceverzameling:
builder.Services.AddValidation();
In de volgende Order klasse is het [ValidatableType] kenmerk vereist voor het modeltype op het hoogste niveau. De andere typen worden automatisch gedetecteerd.
OrderItem en ShippingAddress worden niet weergegeven voor beknoptheid, maar geneste validatie en verzamelingsvalidatie werken op dezelfde manier als ze wel getoond zouden worden.
Order.cs:
using System.ComponentModel.DataAnnotations;
[ValidatableType]
public class Order
{
public Customer Customer { get; set; } = new();
public List<OrderItem> OrderItems { get; set; } = [];
}
public class Customer
{
[Required(ErrorMessage = "Name is required.")]
public string? FullName { get; set; }
[Required(ErrorMessage = "Email is required.")]
public string? Email { get; set; }
public ShippingAddress ShippingAddress { get; set; } = new();
}
In het volgende OrderPage onderdeel is het DataAnnotationsValidator onderdeel aanwezig in het EditForm onderdeel.
OrderPage.razor:
<EditForm Model="Model">
<DataAnnotationsValidator />
<h3>Customer Details</h3>
<div class="mb-3">
<label>
Full Name
<InputText @bind-Value="Model!.Customer.FullName" />
</label>
<ValidationMessage For="@(() => Model!.Customer.FullName)" />
</div>
// ... form continues ...
</EditForm>
@code {
public Order? Model { get; set; }
protected override void OnInitialized() => Model ??= new();
}
De vereiste om de modeltypen buiten Razor onderdelen (.razor bestanden) te declareren, is te wijten aan het feit dat zowel de nieuwe validatiefunctie als de Razor compiler zelf een brongenerator gebruiken. Momenteel kan uitvoer van één brongenerator niet worden gebruikt als invoer voor een andere brongenerator.
Zie de sectie Validatiemodellen uit een andere assembly gebruiken voor hulp bij het gebruik van validatiemodellen uit een andere assembly .
Geneste objecten, verzamelingstypen en complexe typen
Notitie
Voor apps die gericht zijn op .NET 10 of hoger, raden we u niet meer aan het Microsoft.AspNetCore.Components.DataAnnotations.Validation pakket en de methode te gebruiken die in deze sectie wordt beschreven. U wordt aangeraden de ingebouwde validatiefuncties van het DataAnnotationsValidator onderdeel te gebruiken.
Blazor biedt ondersteuning voor het valideren van formulierinvoer met behulp van gegevensaantekeningen met de ingebouwde DataAnnotationsValidator. DataAnnotationsValidator In .NET 9 of eerder worden echter alleen eigenschappen op het hoogste niveau van het model gevalideerd die zijn gebonden aan het formulier dat geen verzamelings- of complexe eigenschappen zijn.
Als u de volledige objectgrafiek van het afhankelijke model wilt valideren, inclusief verzamelings- en complexe eigenschappen, gebruikt u het ObjectGraphDataAnnotationsValidatorexperimenteleMicrosoft.AspNetCore.Components.DataAnnotations.Validation pakket in .NET 9 of eerder:
<EditForm ...>
<ObjectGraphDataAnnotationsValidator />
...
</EditForm>
Aantekeningen toevoegen aan modeleigenschappen met [ValidateComplexType]. In de volgende modelklassen bevat de ShipDescription-klasse aanvullende gegevensaantekeningen om te valideren wanneer het model is gebonden aan het formulier:
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; }
}
Validatiemodellen uit een andere assembly gebruiken
Voor modelvalidatie die is gedefinieerd in een andere assembly, zoals een bibliotheek of het .Client project van een Blazor Web App:
- Als de bibliotheek een gewone klassebibliotheek is (deze is niet gebaseerd op de
Microsoft.NET.Sdk.WebofMicrosoft.NET.Sdk.RazorSDK's), voegt u een pakketreferentie toe aan de bibliotheek voor hetMicrosoft.Extensions.ValidationNuGet-pakket. Aanvullende stappen zijn vereist voor gewone klassebibliotheken, die verderop in deze sectie worden beschreven. - Maak een methode in de bibliotheek of
.Client-project die een IServiceCollection exemplaar als argument ontvangt en roept AddValidation aan. - Roep in de app zowel de methode als AddValidation aan.
De voorgaande benadering resulteert in validatie van de typen van beide assembly's.
In het volgende voorbeeld wordt de AddValidationForTypesInClient methode gemaakt voor het .Client project van een Blazor Web App voor validatie met behulp van typen die in het .Client project zijn gedefinieerd.
ServiceCollectionExtensions.cs (in het .Client project):
namespace BlazorSample.Client.Extensions;
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddValidationForTypesInClient(
this IServiceCollection collection)
{
return collection.AddValidation();
}
}
In het Program bestand van het serverproject, voeg de naamruimte toe en roep de extensiemethode voor serviceverzameling van het .Client project aan (AddValidationForTypesInClient) en AddValidation.
using BlazorSample.Client.Extensions;
...
builder.Services.AddValidationForTypesInClient();
builder.Services.AddValidation();
De nieuwe kenmerken van het Microsoft.Extensions.Validation pakket (ValidatableTypeAttribute en SkipValidationAttribute) worden gepubliceerd als experimenteel in .NET 10. Het pakket is bedoeld om een nieuwe gedeelde infrastructuur te bieden voor validatiefuncties in verschillende frameworks en het publiceren van experimentele typen biedt meer flexibiliteit voor het uiteindelijke ontwerp van de openbare API voor betere ondersteuning bij het gebruik van frameworks.
In Blazor apps worden typen beschikbaar gemaakt via een gegenereerd ingesloten kenmerk. Als een web-app-project dat gebruikmaakt van de Microsoft.NET.Sdk.Web SDK (<Project Sdk="Microsoft.NET.Sdk.Web">) of een RCL die gebruikmaakt van de Microsoft.NET.Sdk.Razor SDK (<Project Sdk="Microsoft.NET.Sdk.Razor">) onderdelen bevat Razor (.razor), genereert het framework automatisch een intern kenmerk binnen het project (Microsoft.Extensions.Validation.Embedded.ValidatableType, ). Microsoft.Extensions.Validation.Embedded.SkipValidation Deze typen zijn uitwisselbaar met de werkelijke kenmerken en niet gemarkeerd als experimenteel. In de meeste gevallen gebruiken ontwikkelaars de [ValidatableType]/[SkipValidation] kenmerken van hun klassen zonder zorgen over hun bron.
De voorgaande benadering is echter niet haalbaar in gewone klassebibliotheken die gebruikmaken van de Microsoft.NET.Sdk SDK (<Project Sdk="Microsoft.NET.Sdk">). Het gebruik van de typen in een gewone klassebibliotheek resulteert in een waarschuwing voor codeanalyse:
ASP0029: 'Microsoft.Extensions.Validation.ValidatableTypeAttribute' is alleen bedoeld voor evaluatiedoeleinden en kan in toekomstige updates worden gewijzigd of verwijderd. Deze diagnose onderdrukken om door te gaan.
De waarschuwing kan worden onderdrukt met behulp van een van de volgende methoden:
Een
<NoWarn>eigenschap in het projectbestand:<PropertyGroup> <NoWarn>$(NoWarn);ASP0029</NoWarn> </PropertyGroup>Een
pragmainstructie waarbij het kenmerk wordt gebruikt:#pragma warning disable ASP0029 [Microsoft.Extensions.Validation.ValidatableType] #pragma warning restore ASP0029Een EditorConfig-bestand (
.editorconfig) regel:dotnet_diagnostic.ASP0029.severity = none
Als het onderdrukken van de waarschuwing niet acceptabel is, maakt u handmatig het embedded attribuut in de bibliotheek aan dat door de web- en Razor SDK's automatisch wordt gegenereerd.
ValidatableTypeAttribute.cs:
namespace Microsoft.Extensions.Validation.Embedded
{
[AttributeUsage(AttributeTargets.Class)]
internal sealed class ValidatableTypeAttribute : Attribute
{
}
}
Gebruik de exacte naamruimte (Microsoft.Extensions.Validation.Embedded) en de klassenaam (ValidatableTypeAttribute) om de validatiebrongenerator het type te detecteren en te gebruiken. U kunt een globale using instructie declareren voor de naamruimte, ofwel met een global using Microsoft.Extensions.Validation.Embedded; instructie of met een <Using Include="Microsoft.Extensions.Validation.Embedded" /> item in het projectbestand van de bibliotheek.
Welke methode ook wordt gebruikt, geeft de aanwezigheid aan van de tijdelijke oplossing voor een toekomstige update van uw code. Framework-updates om de acceptatie van validatietypen in gewone klassebibliotheken te vereenvoudigen, zijn gepland voor .NET 11 (november 2026).
De knop Verzenden inschakelen op basis van formuliervalidatie
Als u de verzendknop wilt in- en uitschakelen op basis van formuliervalidatie, volgt u het volgende voorbeeld:
- Maakt gebruik van een verkorte versie van het eerdere
Starfleet Starship Databaseformulier (Starship3onderdeel) van het voorbeeldformulier in de sectie van het Invoeronderdelen artikel dat alleen een waarde voor het Id van het schip accepteert. De andereStarshipEigenschappen ontvangen geldige standaardwaarden wanneer een instantie van hetStarshiptype wordt gemaakt. - Gebruikt de EditContext van het formulier om het model toe te wijzen wanneer het onderdeel wordt geïnitialiseerd.
- Valideert het formulier in de context van de OnFieldChanged callback om de verzendknop te activeren en te deactiveren.
- Implementeert IDisposable en schrijft de event handler uit in de methode
Dispose. Zie ASP.NET Core Razor component verwijderingvoor meer informatie.
Notitie
Wanneer u een EditForm.EditContext toewijst aan de EditForm.Model, moet u niet ook een EditForm.EditContext toewijzen aan de .
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;
}
}
}
Als een formulier niet vooraf is geladen met geldige waarden en u de knop Submit bij het laden van formulieren wilt uitschakelen, stelt u formInvalid in op true.
Een neveneffect van de voorgaande benadering is dat een validatiesamenvatting (ValidationSummary onderdeel) wordt gevuld met ongeldige velden nadat de gebruiker met één veld heeft gecommuniceerd. Los dit scenario op een van de volgende manieren op:
- Gebruik geen ValidationSummary onderdeel op het formulier.
- Het ValidationSummary onderdeel zichtbaar maken wanneer de knop Verzenden is geselecteerd (bijvoorbeeld in een
Submitmethode).
<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";
}
}
DataAnnotationsValidator validatiegedrag
Het DataAnnotationsValidator onderdeel heeft dezelfde validatievolgorde en een kortsluitingsgedrag als System.ComponentModel.DataAnnotations.Validator. De volgende regels worden toegepast bij het valideren van een exemplaar van het type T:
- Lideigenschappen
Tworden gevalideerd, inclusief recursief valideren van geneste objecten. - Kenmerken
Top typeniveau worden gevalideerd. - De IValidatableObject.Validate methode wordt uitgevoerd als
Tdeze wordt geïmplementeerd.
Als een van de voorgaande stappen een validatiefout produceert, worden de resterende stappen overgeslagen.