Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Hinweis
Dies ist nicht die neueste Version dieses Artikels. Die aktuelle Version finden Sie in der .NET 10-Version dieses Artikels.
Warnung
Diese Version von ASP.NET Core wird nicht mehr unterstützt. Weitere Informationen finden Sie in der .NET- und .NET Core-Supportrichtlinie. Die aktuelle Version finden Sie in der .NET 9-Version dieses Artikels.
In diesem Artikel wird erläutert, wie Sie die Überprüfung in Blazor-Formularen verwenden.
Formularprüfung
In grundlegenden Formularvalidierungsszenarien kann eine EditForm-Instanz deklarierte EditContext- und ValidationMessageStore-Instanzen verwenden, um Formularfelder zu überprüfen. Ein Handler für das OnValidationRequested-Ereignis von EditContext führt eine benutzerdefinierte Validierungslogik aus. Das Ergebnis des Handlers aktualisiert die ValidationMessageStore-Instanz.
Die grundlegende Formularvalidierung ist in Fällen nützlich, in denen das Modell des Formulars in der Komponente definiert ist, die das Formular hostet, entweder als Member direkt in der Komponente oder in einer Unterklasse. Die Verwendung einer Validierungskomponente wird empfohlen, wenn eine unabhängige Modellklasse für mehrere Komponenten verwendet wird.
In Blazor Web Apps erfordert die clientseitige Validierung eine aktive BlazorSignalR-Schaltung. Die clientseitige Überprüfung ist für Formulare in Komponenten, die statisches serverseitiges Rendering (statisches SSR) übernommen haben, nicht verfügbar. Formulare, die statisches SSR übernehmen, werden auf dem Server überprüft, nachdem das Formular gesendet wurde.
In der folgenden Komponente löscht die HandleValidationRequested-Handlermethode alle vorhandenen Validierungsnachrichten, indem sie vor dem Überprüfen des Formulars ValidationMessageStore.Clear aufruft.
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;
}
}
}
Validierungssteuerelementkomponente für Datenanmerkungen und benutzerdefinierte Validierung
Die DataAnnotationsValidator-Komponente fügt einem kaskadierten EditContext Validierung durch Datenanmerkungen hinzu. Zum Aktivieren der Validierung durch Datenanmerkungen ist die DataAnnotationsValidator-Komponente erforderlich. Wenn Sie ein anderes Validierungssystem als Datenanmerkungen verwenden möchten, verwenden Sie eine benutzerdefinierte Implementierung anstelle der DataAnnotationsValidator-Komponente. Die Frameworkimplementierungen für DataAnnotationsValidator können Sie sich in der Verweisquelle ansehen:
Ausführliche Informationen zum Überprüfungsverhalten finden Sie im DataAnnotationsValidator Abschnitt "Überprüfungsverhalten ".
Wenn Sie die Unterstützung für die Validierung von Datenkommentaren für ein EditContext im Code aktivieren müssen, rufen Sie EnableDataAnnotationsValidation mit einem injizierten IServiceProvider (@inject IServiceProvider ServiceProvider) auf dem EditContextauf. Ein erweitertes Beispiel finden Sie in der NotifyPropertyChangedValidationComponent Komponente im ASP.NET Core Blazor Frameworks BasicTestApp (dotnet/aspnetcore GitHub-Repository). In einer Produktionsversion des Beispiels ersetzen Sie das Argument new TestServiceProvider() für den Dienstanbieter durch ein injiziertes IServiceProvider.
Hinweis
Dokumentationslinks zur .NET-Referenzquelle laden in der Regel den Standardbranch des Repositorys, der die aktuelle Entwicklung für das nächste Release von .NET darstellt. Um ein Tag für ein bestimmtes Release auszuwählen, wählen Sie diesen mit der Dropdownliste Switch branches or tags (Branches oder Tags wechseln) aus. Weitere Informationen finden Sie unter How to select a version tag of ASP.NET Core source code (dotnet/AspNetCore.Docs #26205) (Auswählen eines Versionstags von ASP.NET Core-Quellcode (dotnet/AspNetCore.Docs #26205)).
Blazor führt zwei Validierungstypen aus:
- Die Feldvalidierung wird ausgeführt, wenn der Benutzer auf eine Stelle außerhalb des Felds tippt. Während der Feldvalidierung ordnet die DataAnnotationsValidator-Komponente alle gemeldeten Validierungsergebnisse dem Feld zu.
- Modellvalidierung wird ausgeführt, wenn der Benutzer ein Formular sendet. Während der Modellvalidierung versucht die DataAnnotationsValidator-Komponente, das Feld basierend auf dem vom Validierungsergebnis gemeldeten Mitgliedsnamen zu ermitteln. Validierungsergebnisse, die keinem einzelnen Member zugeordnet werden, werden dem Modell und keinem Feld zugeordnet.
In benutzerdefinierten Überprüfungsszenarien:
- Die Validierung verwaltet ein ValidationMessageStore für das EditContexteines Formulars.
- Die DataAnnotationsValidator Komponente wird verwendet, um Validierungsunterstützung an Formulare anzufügen, die auf Validierungsattributen (Datenanmerkungen)basieren.
Es gibt zwei allgemeine Ansätze zum Erreichen der benutzerdefinierten Validierung, die in den nächsten beiden Abschnitten dieses Artikels beschrieben werden:
-
Manuelle Überprüfung mithilfe des
OnValidationRequested-Ereignisses: Manuelle Überprüfung der Felder eines Formulars mit Datenanmerkungsüberprüfung und benutzerdefiniertem Code für Feldprüfungen, wenn die Überprüfung über einen Ereignishandler angefordert wird, der dem OnValidationRequested-Ereignis zugewiesen ist. - Validator-Komponenten: Eine oder mehrere benutzerdefinierte Validatorkomponenten können verwendet werden, um die Überprüfung für verschiedene Formulare auf derselben Seite oder dasselbe Formular bei verschiedenen Schritten der Formularverarbeitung zu verarbeiten (z. B. clientvalidierung gefolgt von der Serverüberprüfung).
Manuelle Überprüfung mithilfe des OnValidationRequested-Ereignisses
Sie können ein Formular manuell validieren, indem Sie einen benutzerdefinierten Ereignishandler verwenden, der dem EditContext.OnValidationRequested-Ereignis zugewiesen ist, um ein ValidationMessageStorezu verwalten.
Das Blazor-Framework bietet die DataAnnotationsValidator-Komponente, um Formulare auf der Grundlage von Validierungsattributen (Datenannotationen)mit zusätzlicher Validierungsunterstützung zu versehen.
Unter Hinweis auf das frühere Starship8 Komponentenbeispiel wird die HandleValidationRequested Methode OnValidationRequestedzugewiesen, wo Sie eine manuelle Überprüfung im C#-Code ausführen können. Einige Änderungen zeigen, wie man die vorhandene manuelle Überprüfung mit der Überprüfung durch Datenanmerkungen unter Verwendung von DataAnnotationsValidator und einem Überprüfungsattribut, das auf das Holodeck-Modell angewendet wird, kombiniert.
Verweisen Sie auf den System.ComponentModel.DataAnnotations-Namensraum in den Razor-Direktiven der Komponente am Anfang der Komponentendefinitionsdatei:
@using System.ComponentModel.DataAnnotations
Fügen Sie dem Id-Modell eine Holodeck-Eigenschaft mit einem Überprüfungsattribut hinzu, um die Länge der Zeichenfolge auf sechs Zeichen zu beschränken:
[StringLength(6)]
public string? Id { get; set; }
Fügen Sie dem Formular eine DataAnnotationsValidator Komponente (<DataAnnotationsValidator />) hinzu. In der Regel wird die Komponente direkt unter dem <EditForm>-Tag platziert, Sie können sie jedoch an einer beliebigen Stelle im Formular platzieren:
<DataAnnotationsValidator />
Ändern Sie das Sendeverhalten des Formulars im tag <EditForm> von OnSubmit in OnValidSubmit, wodurch sichergestellt wird, dass das Formular gültig ist, bevor die zugewiesene Ereignishandlermethode ausgeführt wird:
- OnSubmit="Submit"
+ OnValidSubmit="Submit"
Fügen Sie im <EditForm>ein Feld für die eigenschaft Id hinzu:
<div>
<label>
<InputText @bind-Value="Model!.Id" />
ID (6 characters max)
</label>
<ValidationMessage For="() => Model!.Id" />
</div>
Nachdem Sie die vorherigen Änderungen vorgenommen haben, entspricht das Verhalten des Formulars der folgenden Spezifikation:
- Die Überprüfung der Datenanmerkungen für die
Id-Eigenschaft löst keinen Überprüfungsfehler aus, wenn dasIdFeld lediglich den Fokus verliert. Die Überprüfung wird ausgeführt, wenn der Benutzer die SchaltflächeUpdateauswählt. - Jede manuelle Überprüfung, die Sie in der
HandleValidationRequestedMethode ausführen möchten, die dem OnValidationRequested Ereignis des Formulars zugewiesen ist, wird ausgeführt, wenn der Benutzer die SchaltflächeUpdatedes Formulars auswählt. Im vorhandenen Code desStarship8Komponentenbeispiels muss der Benutzer entweder oder beide Kontrollkästchen auswählen, um das Formular zu überprüfen. - Das Formular verarbeitet die
SubmitMethode erst, wenn sowohl die Datenanmerkungen als auch die manuelle Validierung bestanden wurden.
Validatorkomponenten
Validierungssteuerelementkomponenten unterstützen Formularvalidierung durch die Verwaltung eines ValidationMessageStore für den EditContext eines Formulars.
Das Blazor-Framework stellt die DataAnnotationsValidator-Komponente zum Anfügen von Validierungsunterstützung zu Formularen auf der Grundlage von Validierungsattributen (Datenanmerkungen) zur Verfügung. Sie können Komponenten für benutzerdefinierte Validierungssteuerelemente erstellen, um Validierungsmeldungen für verschiedene Formulare auf derselben Seite oder im selben Formular in verschiedenen Schritten der Formularverarbeitung zu verarbeiten, z. B. Clientvalidierung gefolgt von Servervalidierung. Das in diesem Abschnitt gezeigte Beispiel für eine Validierungssteuerelementkomponente (CustomValidation) wird in den folgenden Abschnitten dieses Artikels verwendet:
- Geschäftslogikvaliderung mit einer Validierungskomponente
- Servervaliderung mit einer Validierungskomponente
Von den in Datenanmerkungen integrierten Validatoren wird nur das [Remote]-Überprüfungsattribut in Blazor nicht unterstützt.
Hinweis
In vielen Fällen können benutzerdefinierte Validierungsattribute für Datenanmerkungen anstelle von benutzerdefinierten Validator-Komponenten verwendet werden. Benutzerdefinierte Attribute, die auf das Modell des Formulars angewendet werden, werden mit der Verwendung der DataAnnotationsValidator-Komponente aktiviert. Bei Verwendung mit Servervalidierung müssen alle benutzerdefinierten Attribute, die auf das Modell angewendet werden, auf dem Server ausführbar sein. Weitere Informationen finden Sie im Abschnitt Benutzerdefinierte Validierungsattribute.
Erstellen Sie eine Validator-Komponente aus ComponentBase:
- Der EditContext des Formulars ist ein kaskadierender Parameter der Komponente.
- Wenn die Validierungskomponente initialisiert wird, wird ein neuer ValidationMessageStore erstellt, um eine aktuelle Liste der Formular-Fehler zu verwalten.
- Der Nachrichtenspeicher empfängt Fehler, wenn Entwicklercode in der Komponente des Formulars die
DisplayErrors-Methode aufruft. Die Fehler werden an dieDisplayErrors-Methode in einemDictionary<string, List<string>>übergeben. Im Wörterbuch ist der Schlüssel der Name des Formularfelds, das mindestens einen Fehler aufweist. Der Wert ist die Fehlerliste. - Meldungen werden gelöscht, wenn eines der folgenden Ereignisse aufgetreten ist:
- Validierung wird für den EditContext angefordert, wenn das OnValidationRequested-Ereignis ausgelöst wird. Alle Fehler werden gelöscht.
- Ein Feld ändert sich im Formular, wenn das OnFieldChanged-Ereignis ausgelöst wird. Nur die Fehler für das Feld werden gelöscht.
- Die
ClearErrors-Methode wird vom Entwicklercode aufgerufen. Alle Fehler werden gelöscht.
Aktualisieren Sie den Namespace in der folgenden Klasse so, dass er dem Namespace Ihrer App entspricht.
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();
}
}
Wichtig
Beim Ableiten von ist die Angabe eines Namespace ComponentBase. Wenn kein Namespace angegeben wird, führt dies zu einem Buildfehler:
Tag helpers cannot target tag name '<global namespace>.{CLASS NAME}' because it contains a ' ' character.
Der Platzhalter {CLASS NAME} ist der Name der Komponentenklasse. Im Beispiel für einen benutzerdefinierten Validator in diesem Abschnitt wird der Beispiel-Namespace BlazorSample angegeben.
Hinweis
Im obigen Beispiel sind anonyme Lambdaausdrücke registrierte Ereignishandler für OnValidationRequested und OnFieldChanged. In diesem Szenario muss IDisposable nicht implementiert und das Abonnement der Ereignisdelegate nicht beendet werden. Weitere Informationen finden Sie unter ASP.NET Core Razor Komponentenentsorgung.
Geschäftslogikvaliderung mit einer Validierungskomponente
Verwenden Sie zur allgemeinen Validierung der Geschäftslogik eine Validator-Komponente, die Formularfehler in einem Wörterbuch empfängt.
Die grundlegende Validierung ist in Fällen nützlich, in denen das Modell des Formulars in der Komponente definiert ist, die das Formular hostet, entweder als Member direkt in der Komponente oder in einer Unterklasse. Die Verwendung einer Validierungskomponente wird empfohlen, wenn eine unabhängige Modellklasse für mehrere Komponenten verwendet wird.
Im folgenden Beispiel:
- Es wird eine verkürzte Version des
Starfleet Starship Database-Formulars (Starship3-Komponente) aus dem Abschnitt Beispielformular im Artikel Eingabekomponenten verwendet, die nur die Klassifizierung und Beschreibung des Raumfahrzeugs akzeptiert. Die Validierung von Datenkommentaren wird bei der Übermittlung des Formulars nicht ausgelöst, da die Komponente DataAnnotationsValidator nicht im Formular enthalten ist. - Die Komponente
CustomValidationaus dem Abschnitt Validator-Komponenten dieses Artikels wird verwendet. - Die Validierung erfordert einen Wert für die Beschreibung des Schiffs (
Description), wenn der Benutzer die Schiffsklassifizierung (Defense) „Classification“ auswählt.
Wenn Validierungsmeldungen in der Komponente festgelegt werden, werden sie dem ValidationMessageStore des Validators hinzugefügt und in der Validierungszusammenfassung des EditForm angezeigt.
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");
}
}
}
Hinweis
Als Alternative zur Verwendung von Validierungkomponenten können Datenanmerkungs-Validierungsattribute verwendet werden. Benutzerdefinierte Attribute, die auf das Modell des Formulars angewendet werden, werden mit der Verwendung der DataAnnotationsValidator-Komponente aktiviert. Bei Verwendung mit Servervalidierung müssen die Attribute auf dem Server ausführbar sein. Weitere Informationen finden Sie im Abschnitt Benutzerdefinierte Validierungsattribute.
Servervaliderung mit einer Validierungskomponente
In diesem Abschnitt geht es primär um Blazor Web App-Szenarien, aber der gleiche allgemeine Ansatz wird für jede Art von App verwendet, die eine Servervalidierung mit der Web-API nutzt.
In diesem Abschnitt geht es primär um gehostete Blazor WebAssembly-Szenarien, aber der gleiche allgemeine Ansatz wird für jede Art von App verwendet, die eine Servervalidierung mit der Web-API nutzt.
Die Servervalidierung wird zusätzlich zur Clientvalidierung unterstützt:
- Verarbeiten Sie die Clientvalidierung im Formular mit der DataAnnotationsValidator-Komponente.
- Wenn das Formular die Clientvalidierung besteht (OnValidSubmit wird aufgerufen), senden Sie EditContext.Model zur Formularverarbeitung an eine Back-End-Server-API.
- Validierung des Prozessmodells auf dem Server.
- Die Server-API umfasst sowohl die integrierte Framework-Datenanmerkungsvalidierung als auch benutzerdefinierte Validierungslogik, die vom Entwickler bereitgestellt wird. Wenn die Validierung auf dem Server bestanden wird, wird das Formular verarbeitet und ein Erfolgsstatuscode zurückgesendet (
200 - OK). Wenn die Validierung fehlschlägt, werden ein Fehlerstatuscode (400 - Bad Request) und die Feldvalidierungsfehler zurückgegeben. - Deaktivieren Sie entweder das Formular bei Erfolg, oder zeigen Sie die Fehler an.
Die grundlegende Validierung ist in Fällen nützlich, in denen das Modell des Formulars in der Komponente definiert ist, die das Formular hostet, entweder als Member direkt in der Komponente oder in einer Unterklasse. Die Verwendung einer Validierungskomponente wird empfohlen, wenn eine unabhängige Modellklasse für mehrere Komponenten verwendet wird.
Das folgende Beispiel beruht auf Folgendem:
- Ein Blazor Web App mit interaktiven WebAssembly-Komponenten, die aus der Blazor Web App Projektvorlageerstellt wurden.
- Das
Starship-Modell (Starship.cs) aus dem Abschnitt Beispielformular des Artikels Eingabekomponenten - Die
CustomValidation-Komponente, die im Abschnitt Validator-Komponenten gezeigt wird.
Platzieren Sie das Starship-Modell (Starship.cs) in einem freigegebenen Klassenbibliotheksprojekt, damit sowohl Client- als auch Serverprojekte das Modell verwenden können. Fügen Sie den Namespace hinzu, oder aktualisieren Sie ihn so, dass er mit dem Namespace der freigegebenen App (z. B. namespace BlazorSample.Shared) übereinstimmt. Da für das Modell Datenanmerkungen erforderlich sind, vergewissern Sie sich, dass die freigegebene Klassenbibliothek das freigegebene Framework verwendet, oder fügen Sie das System.ComponentModel.Annotations-Paket dem freigegebenen Projekt hinzu.
Hinweis
Eine Anleitung zum Hinzufügen von Paketen zu .NET-Anwendungen finden Sie in den Artikeln unter Pakete installieren und verwalten unter Workflow für die Paketnutzung (NuGet-Dokumentation). Überprüfen Sie unter NuGet.org, ob die richtige Paketversion verwendet wird.
Fügen Sie im Hauptprojekt des Blazor Web Appeinen Controller hinzu, der Validierungsanfragen für Raumschiffe verarbeitet und Meldungen über fehlgeschlagene Validierungen zurückgibt. Aktualisieren Sie die Namespaces in der letzten using-Anweisung für das freigegebene Klassenbibliotheksprojekt und in der namespace-Anweisung für die Controllerklasse. Zusätzlich zur Client- und Servervalidierung durch Datenanmerkungen überprüft der Controller, ob ein Wert für die Beschreibung des Schiffs (Description) angegeben ist, wenn der oder die Benutzer*in die Schiffsklassifizierung Defense (Classification) auswählt.
- Einer gehosteten Blazor WebAssemblyLösung, die auf Grundlage der Blazor WebAssembly-Projektvorlage erstellt wurde. Der Ansatz wird für alle sicheren gehosteten Blazor-Lösungen unterstützt, die in der Dokumentation zur gehosteten Blazor WebAssembly-Sicherheit beschrieben sind.
- Das
Starship-Modell (Starship.cs) aus dem Abschnitt Beispielformular des Artikels Eingabekomponenten - Die
CustomValidation-Komponente, die im Abschnitt Validator-Komponenten gezeigt wird.
Platzieren Sie das Starship-Modell (Starship.cs) im Shared -Projekt der Lösung, sodass sowohl die Client- als auch die Server-App das Modell verwenden kann. Fügen Sie den Namespace hinzu, oder aktualisieren Sie ihn so, dass er mit dem Namespace der freigegebenen App (z. B. namespace BlazorSample.Shared) übereinstimmt. Fügen Sie das Paket System.ComponentModel.Annotations dem Projekt Shared hinzu, da das Modell Datenanmerkungen erfordert.
Hinweis
Eine Anleitung zum Hinzufügen von Paketen zu .NET-Anwendungen finden Sie in den Artikeln unter Pakete installieren und verwalten unter Workflow für die Paketnutzung (NuGet-Dokumentation). Überprüfen Sie unter NuGet.org, ob die richtige Paketversion verwendet wird.
Fügen Sie im Server -Projekt einen Controller hinzu, um die Anforderungen für die Validierung von „Starship“ zu verarbeiten und bei Validierungsfehlern Meldungen zurückzugeben. Aktualisieren Sie die Namespaces in der letzten using-Anweisung sowohl für das Shared-Projekt als auch für die namespace-Controllerklasse. Zusätzlich zur Client- und Servervalidierung durch Datenanmerkungen überprüft der Controller, ob ein Wert für die Beschreibung des Schiffs (Description) angegeben ist, wenn der oder die Benutzer*in die Schiffsklassifizierung Defense (Classification) auswählt.
Die Validierung für die Schiffsklassifizierung Defense erfolgt nur serverseitig im Controller, da das anstehende Formular clientseitig nicht dieselbe Validierung ausführt, wenn das Formular an den Server übermittelt wird. Die Serverüberprüfung ohne Clientüberprüfung ist in Apps üblich, die eine private Überprüfung der Geschäftslogik von Benutzereingaben auf dem Server erfordern. Beispielsweise können private Informationen aus Daten, die für einen Benutzer gespeichert sind, erforderlich sein, um Benutzereingaben zu überprüfen. Private Daten können offensichtlich nicht zur Clientvalidierung an den Client gesendet werden.
Hinweis
Der StarshipValidation-Controller in diesem Abschnitt verwendet Microsoft Identity 2.0. Die Web-API akzeptiert nur Token für Benutzer, die den Bereich API.Access für diese API besitzen. Eine zusätzliche Anpassung ist erforderlich, wenn sich der Bereichsname der API von API.Access unterscheidet.
Weitere Informationen zur Sicherheit finden Sie unter:
- ASP.NET Core Blazor Authentifizierung und Autorisierung (und die anderen Artikel im Knoten BlazorSicherheit und Identity )
- Microsoft Identity Platform-Dokumentation
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);
}
}
Überprüfen Sie, ob der Namespace des vorherigen Controllers (BlazorSample.Server.Controllers) mit dem Namespace des Controllers der App übereinstimmt, oder aktualisieren Sie ihn.
Wenn ein Validierungsfehler bei der Modellbindung auf dem Server auftritt, gibt ein ApiController (ApiControllerAttribute) normalerweise eine Standardantwort „Ungültige Anforderung“ mit ValidationProblemDetails zurück. Die Antwort enthält mehr Daten als nur die Validierungsfehler (wie im folgenden Beispiel gezeigt), wenn alle Felder des Starfleet Starship Database-Formulars nicht übermittelt wurden und die Validierung des Formulars fehlschlägt:
{
"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)." ]
}
}
Hinweis
Um die vorangehende JSON-Antwort zu veranschaulichen, müssen Sie entweder die Clientvalidierung des Formulars deaktivieren, um die Übermittlung leerer Feldformulare zu ermöglichen, oder ein Tool verwenden, um eine Anforderung direkt an die Server-API zu senden, z. B. Firefox Browser Developer.
Wenn die Server-API die vorherige JSON-Standardantwort zurückgibt, ist es möglich, dass der Client die Antwort im Entwicklercode analysiert, um die untergeordneten Elemente des errors-Knotens für die Verarbeitung von Formularvalidierungsfehlern abzurufen. Es ist unpraktisch, Entwicklercode zu schreiben, um die Datei zu analysieren. Das manuelle Parsen des JSON erfordert nach dem Aufruf von Dictionary<string, List<string>>eine ReadFromJsonAsync Fehlermeldung. Im Idealfall sollte die Server-API nur die Überprüfungsfehler zurückgeben, wie im folgenden Beispiel gezeigt:
{
"Id": [ "The Id field is required." ],
"Classification": [ "The Classification field is required." ],
"IsValidatedDesign": [ "This form disallows unapproved ships." ],
"MaximumAccommodation": [ "Accommodation invalid (1-100000)." ]
}
Um die Antwort der Server-API so zu ändern, dass sie nur die Validierungsfehler zurückgibt, ändern Sie den Delegaten, der bei Aktionen aufgerufen wird, die mit ApiControllerAttribute in der Datei Program annotiert sind. Geben Sie für den API-Endpunkt (/StarshipValidation) ein BadRequestObjectResult mit ModelStateDictionary zurück. Behalten Sie für alle anderen API-Endpunkte das Standardverhalten bei, indem Sie das Objektergebnis mit einem neuen ValidationProblemDetails zurückgeben.
Fügen Sie den Microsoft.AspNetCore.Mvc-Namespace am Anfang der Datei Program im Hauptprojekt der Blazor Web App hinzu:
using Microsoft.AspNetCore.Mvc;
Fügen Sie in der Datei Program die folgende AddControllersWithViews-Erweiterungsmethode hinzu, oder aktualisieren Sie sie, und fügen Sie den folgenden Aufruf von ConfigureApiBehaviorOptions ein:
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));
}
};
});
Wenn Sie dem Hauptprojekt des Blazor Web App zum ersten Mal Controller hinzufügen, ordnen Sie die Controller-Endpunkte zu, wenn Sie den vorangehenden Code platzieren, der die Dienste für die Controller registriert. Im folgenden Beispiel werden Standardcontrollerrouten verwendet:
app.MapDefaultControllerRoute();
Hinweis
Im obigen Beispiel werden Controllerdienste explizit registriert, indem AddControllersWithViews aufgerufen wird, um automatisch XSRF/CSRF-Angriffe (Cross-Site Request Forgery, websiteübergreifende Anforderungsfälschung) abzumildern. Wenn Sie nur AddControllers verwenden, wird der Fälschungsschutz nicht automatisch aktiviert.
Weitere Informationen zur Reaktion auf Fehler beim Controllerrouting und bei Überprüfungen finden Sie in den folgenden Ressourcen:
Fügen Sie im .Client-Projekt die im Abschnitt "Validator-Komponenten" gezeigte CustomValidation-Komponente hinzu. Aktualisieren Sie den Namespace so, dass er mit dem der App (z. B.namespace BlazorSample.Client) übereinstimmt.
Im .Client -Projekt wird das Starfleet Starship Database-Formular aktualisiert, um Servervalidierungsfehler mithilfe der CustomValidation-Komponente anzuzeigen. Wenn die Server-API Validierungsmeldungen zurückgibt, werden diese dem CustomValidation der ValidationMessageStore-Komponente hinzugefügt. Die Fehler sind im EditContext des Formulars zur Anzeige durch die Validierungszusammenfassung des Formulars verfügbar.
Ändern Sie in der folgenden Komponente den Namespace des freigegebenen Projekts (@using BlazorSample.Shared) in den Namespace des freigegebenen Projekts. Beachten Sie, dass das Formular eine Autorisierung erfordert, weshalb der Benutzer bei der App angemeldet sein muss, um zum Formular navigieren zu können.
Fügen Sie den Microsoft.AspNetCore.Mvc-Namespace am Anfang der Datei Program in der Server -App hinzu:
using Microsoft.AspNetCore.Mvc;
Suchen Sie in der Datei Program nach der Erweiterungsmethode AddControllersWithViews und fügen Sie den folgenden Aufruf zu ConfigureApiBehaviorOptions hinzu:
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));
}
};
});
Hinweis
Im obigen Beispiel werden Controllerdienste explizit registriert, indem AddControllersWithViews aufgerufen wird, um automatisch XSRF/CSRF-Angriffe (Cross-Site Request Forgery, websiteübergreifende Anforderungsfälschung) abzumildern. Wenn Sie nur AddControllers verwenden, wird der Fälschungsschutz nicht automatisch aktiviert.
Fügen Sie im Client-Projekt die im Abschnitt "Validator-Komponenten" gezeigte CustomValidation-Komponente hinzu. Aktualisieren Sie den Namespace so, dass er mit dem der App (z. B.namespace BlazorSample.Client) übereinstimmt.
Im Client -Projekt wird das Starfleet Starship Database-Formular aktualisiert, um Servervalidierungsfehler mithilfe der CustomValidation-Komponente anzuzeigen. Wenn die Server-API Validierungsmeldungen zurückgibt, werden diese dem CustomValidation der ValidationMessageStore-Komponente hinzugefügt. Die Fehler sind im EditContext des Formulars zur Anzeige durch die Validierungszusammenfassung des Formulars verfügbar.
Aktualisieren Sie in der folgenden Komponente den Namespace des Shared-Projekts (@using BlazorSample.Shared) auf den Namespace des gemeinsam genutzten Projekts. Beachten Sie, dass das Formular eine Autorisierung erfordert, weshalb der Benutzer bei der App angemeldet sein muss, um zum Formular navigieren zu können.
Starship10.razor:
Hinweis
Formulare, die auf EditForm basieren, aktivieren automatisch den Schutz vor Fälschung. Der Controller sollte AddControllersWithViews zum Registrieren von Controllerdiensten verwenden und die Unterstützung für den Schutz vor Fälschung für die Web-API automatisch aktivieren.
@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.";
}
}
}
Das .Client-Projekt eines Blazor Web App muss auch ein HttpClient für HTTP POST-Anfragen an einen Backend-Web-API-Controller registrieren. Überprüfen Sie Folgendes in der Datei .Client des Program-Projekts, oder fügen Sie es hinzu:
builder.Services.AddScoped(sp =>
new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
Im vorherigen Beispiel wird die Basisadresse mit builder.HostEnvironment.BaseAddress (IWebAssemblyHostEnvironment.BaseAddress) festgelegt, wodurch die Basisadresse für die App abgerufen und in der Regel vom <base>-Wert des href-Tags auf der Hostseite abgeleitet wird.
@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.";
}
}
}
Hinweis
Als Alternative zur Verwendung einer Validierungskomponente können Validierungsattribute von Datenanmerkungen verwendet werden. Benutzerdefinierte Attribute, die auf das Modell des Formulars angewendet werden, werden mit der Verwendung der DataAnnotationsValidator-Komponente aktiviert. Bei Verwendung mit Servervalidierung müssen die Attribute auf dem Server ausführbar sein. Weitere Informationen finden Sie im Abschnitt Benutzerdefinierte Validierungsattribute.
Hinweis
Der Servervalidierungsansatz in diesem Abschnitt eignet sich für jedes der Beispiele für gehostete Blazor WebAssembly-Lösungen in dieser Dokumentation:
InputText basierend auf dem Eingabeereignis
Verwenden Sie die InputText-Komponente, um eine benutzerdefinierte Komponente zu erstellen, die das oninput-Ereignis (input) anstelle des onchange-Ereignisses (change) nutzt. Die Verwendung des input-Ereignisses löst die Feldvalidierung bei jeder Tastatureingabe aus.
Die folgende CustomInputText-Komponente erbt die InputText-Komponente des Frameworks und legt die Ereignisbindung auf das oninput-Ereignis (input) fest.
CustomInputText.razor:
@inherits InputText
<input @attributes="AdditionalAttributes"
class="@CssClass"
@bind="CurrentValueAsString"
@bind:event="oninput" />
Die CustomInputText-Komponente kann überall dort verwendet werden, wo InputText verwendet wird. Die folgende Komponente verwendet die gemeinsam genutzte CustomInputText-Komponente.
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; }
}
}
Komponenten der Validierungszusammenfassung und der Validierungsnachricht
Die ValidationSummary-Komponente fasst alle Validierungsnachrichten zusammen. Das ähnelt dem Taghilfsprogramm für Validierungszusammenfassungen:
<ValidationSummary />
Validierungsmeldungen für ein bestimmtes Modell werden mit dem Model-Parameter ausgegeben:
<ValidationSummary Model="Model" />
Die ValidationMessage<TValue>-Komponente zeigt Validierungsnachrichten für ein bestimmtes Feld an. Das ähnelt dem Taghilfsprogramm für Validierungsmeldungen. Das Validierungsfeld wird mit dem For-Attribut und einem Lambdaausdruck angegeben, der die Modelleigenschaft benennt:
<ValidationMessage For="@(() => Model!.MaximumAccommodation)" />
Die ValidationMessage<TValue>- und ValidationSummary-Komponenten unterstützen arbiträre Attribute. Attribute, die nicht mit einem Komponentenparameter übereinstimmen, werden dem gerenderten <div>- oder <ul>-Element hinzugefügt.
Steuern Sie den Stil von Validierungsmeldungen im Stylesheet (wwwroot/css/app.css oder wwwroot/css/site.css) der App. Die validation-message-Standardklasse legt die Textfarbe von Validierungsmeldungen auf Rot fest:
.validation-message {
color: red;
}
Ermitteln der Gültigkeit eines Formularfelds
Verwenden Sie EditContext.IsValid, um zu ermitteln, ob ein Feld gültig ist, ohne Validierungsmeldungen abzurufen.
wird unterstützt, aber nicht empfohlen:
var isValid = !editContext.GetValidationMessages(fieldIdentifier).Any();
empfohlen:
var isValid = editContext.IsValid(fieldIdentifier);
Benutzerdefinierte Validierungsattribute
Übergeben Sie die -Eigenschaft des Validierungskontexts bei der Erstellung der MemberName-Klasse, um sicherzustellen, dass ein Validierungsergebnis korrekt einem Feld zugeordnet wird, wenn ein ValidationResult verwendet wird.
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 });
}
}
Fügen Sie über ValidationContext Dienste in benutzerdefinierte Validierungsattribute ein. Das folgende Beispiel demonstriert ein SaladChef-Formular, das Benutzereingaben mit Abhängigkeitsinjektion (Dependency Injection, DI) validiert.
Die SaladChef-Klasse gibt die genehmigte Zutatenliste für einen Ten Forward-Salat auf dem Sternenschiff an.
SaladChef.cs:
namespace BlazorSample;
public class SaladChef
{
public string[] SaladToppers = { "Horva", "Kanda Root", "Krintar", "Plomeek",
"Syto Bean" };
}
Registrieren Sie SaladChef im DI-Container der App in der Datei Program:
builder.Services.AddTransient<SaladChef>();
Die IsValid-Methode der folgenden SaladChefValidatorAttribute-Klasse ruft den Dienst SaladChef aus DI ab, um die Eingaben des Benutzers zu prüfen.
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));
}
}
Die folgende Komponente validiert Benutzereingaben, indem sie das SaladChefValidatorAttribute ([SaladChefValidator]) auf die Zeichenfolge für Salatzutaten (SaladIngredient) anwendet.
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);
}
Benutzerdefinierte CSS-Klassenattribute für die Validierung
CSS-Klassenattribute für die benutzerdefinierte Validierung sind nützlich, wenn eine Integration in CSS-Frameworks wie Bootstrap erfolgt.
Um CSS-Klassenattribute für die benutzerdefinierte Validierung anzugeben, geben Sie zunächst CSS-Stile für die benutzerdefinierte Validierung an. Im folgenden Beispiel werden Stile für „gültig“ (validField) und für „ungültig“ (invalidField) angegeben.
Fügen Sie die folgenden CSS-Klassen zur Formatvorlage der App hinzu:
.validField {
border-color: lawngreen;
}
.invalidField {
background-color: tomato;
}
Erstellen Sie eine von FieldCssClassProvider abgeleitete Klasse, die auf Feldvalidierungsmeldungen prüft und den entsprechenden Stil für „gültig“ oder „ungültig“ anwendet.
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";
}
}
Legen Sie die CustomFieldClassProvider-Klasse als CSS-Klassenanbieter für Felder auf der EditContext-Instanz des Formulars mit SetFieldCssClassProvider fest.
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; }
}
}
Im vorherigen Beispiel wird die Gültigkeit aller Formularfelder überprüft und auf jedes Feld ein Stil angewendet. Wenn das Formular benutzerdefinierte Stile nur auf eine Teilmenge der Felder anwenden soll, lassen Sie CustomFieldClassProvider Stile bedingt anwenden. Im folgenden CustomFieldClassProvider2-Beispiel wird ein Stil nur auf das Feld Name angewendet. Für Felder, deren Namen nicht Name entsprechen, wird string.Empty zurückgegeben, und es wird kein Stil angewendet. Mithilfe der Reflexion wird das Feld mit der Eigenschaft oder dem Feldnamen des Modellelements abgeglichen, und nicht mit einer der HTML-Entität zugewiesenen id.
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;
}
}
Hinweis
Beim Abgleich des Feldnamens im vorherigen Beispiel wird die Groß-/Kleinschreibung beachtet, sodass ein Modelleigenschaftenmember, der als „Name“ festgelegt ist, einer bedingten Überprüfung von „Name“ entsprechen muss:
-
Stimmt überein:
fieldId.FieldName == "Name" -
Stimmt nicht überein:
fieldId.FieldName == "name" -
Stimmt nicht überein:
fieldId.FieldName == "NAME" -
Stimmt nicht überein:
fieldId.FieldName == "nAmE"
Fügen Sie Model eine zusätzliche Eigenschaft hinzu, z. B.:
[StringLength(10, ErrorMessage = "Description is too long.")]
public string? Description { get; set; }
Fügen Sie Description dem Formular der CustomValidationForm-Komponente hinzu.
<InputText @bind-Value="Model!.Description" />
Aktualisieren Sie die EditContext-Instanz in der OnInitialized-Methode der Komponente, um den neuen CSS-Klassenanbieter für Felder zu verwenden:
editContext?.SetFieldCssClassProvider(new CustomFieldClassProvider2());
Da eine CSS-Validierungsklasse nicht auf das Feld Description angewendet wird, wird sie nicht formatiert. Die Feldvalidierung wird jedoch normal ausgeführt. Wenn mehr als 10 Zeichen angegeben werden, gibt die Validierungszusammenfassung den Fehler an:
Die Beschreibung ist zu lang.
Im folgenden Beispiel:
Der benutzerdefinierte CSS-Stil wird auf das
Name-Feld angewendet.Alle anderen Felder wenden eine Logik ähnlich der Standardlogik von Blazor an und verwenden die CSS-Validierungsstile des Standardfelds von Blazor mit
modified,validoderinvalid. Beachten Sie, dass Sie für die Standardstile diese nicht dem Stylesheet der App hinzufügen müssen, wenn die App auf einer Blazor-Projektvorlage basiert. Für Apps, die nicht auf einer Blazor-Projektvorlage basieren, können die Standardstile dem Stylesheet der App hinzugefügt werden:.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";
}
}
}
}
Aktualisieren Sie die EditContext-Instanz in der OnInitialized-Methode der Komponente, um den vorherigen CSS-Klassenanbieter für Felder zu verwenden:
editContext.SetFieldCssClassProvider(new CustomFieldClassProvider3());
Verwenden von CustomFieldClassProvider3:
- Das
Name-Feld verwendet die benutzerdefinierten CSS-Validierungsstile der App. - Das
Description-Feld verwendet Logik ähnlich der Logik von Blazor und die CSS-Validierungsstile des Standardfelds von Blazor.
Validierung auf Klassenebene mit IValidatableObject
Die Überprüfung auf Klassenebene mit IValidatableObject (API-Dokumentation) wird für Blazor-Formularmodelle unterstützt. Die IValidatableObject-Überprüfung wird nur ausgeführt, wenn das Formular übermittelt wird und nur dann, wenn alle anderen Überprüfungen erfolgreich sind.
Blazor Validierungspaket für Datenanmerkungen
Hinweis
Das Microsoft.AspNetCore.Components.DataAnnotations.Validation Paket wird für Apps, die auf .NET 10 oder höher abzielen, nicht mehr empfohlen. Weitere Informationen finden Sie im Abschnitt " Geschachtelte Objekte,Auflistungstypen und komplexe Typen ".
Das Microsoft.AspNetCore.Components.DataAnnotations.Validation Paket füllt Überprüfungslücken mithilfe der DataAnnotationsValidator Komponente. Das Paket ist aktuell experimentell.
Warnung
Das Microsoft.AspNetCore.Components.DataAnnotations.Validation Paket verfügt über eine neueste Version des Releasekandidaten bei NuGet.org. Verwenden Sie zurzeit weiterhin das experimentelle Release-Kandidatenpaket. Experimentelle Features werden für die Untersuchung der Funktionsfähigkeit von Features bereitgestellt und dürfen nicht in einer stabilen Version enthalten sein. Weitere Aktualisierungen finden Sie im GitHub-Repository „Ankündigungen“, im dotnet/aspnetcoreRepository von GitHub oder in diesem Themenabschnitt.
[CompareProperty]-Attribut
Das CompareAttribute funktioniert nicht gut mit der DataAnnotationsValidator-Komponente, weil das DataAnnotationsValidator das Validierungsergebnis nicht mit einem bestimmten Mitglied verknüpft. Das kann zu einem inkonsistenten Verhalten zwischen der Validierung auf Feldebene und der Validierung des gesamten Modells bei der Einreichung führen. Das Microsoft.AspNetCore.Components.DataAnnotations.Validation experimentelle Paket führt ein zusätzliches Validierungsattribut ein, ComparePropertyAttributedas um diese Einschränkungen herum funktioniert. In einer Blazor Anwendung ist [CompareProperty] ein direkter Ersatz für das [Compare] Attribut.
Geschachtelte Objekte und Sammlungstypen
Blazor Die Formularüberprüfung enthält Unterstützung für die Überprüfung von Eigenschaften geschachtelter Objekte und Collection-Items mit dem integrierten DataAnnotationsValidator.
Um ein validiertes Formular zu erstellen, verwenden Sie eine DataAnnotationsValidator Komponente innerhalb einer EditForm Komponente genau wie zuvor.
So aktivieren Sie die Validierungsfunktion für geschachtelte Objekte und Sammlungstypen:
- Rufen Sie die Erweiterungsmethode in der AddValidation Datei auf, in der
ProgramDienste registriert sind. - Deklarieren Sie die Formularmodelltypen in einer C#-Klassendatei, nicht in einer Razor Komponente (
.razor). - Kommentieren Sie den Stammformularmodelltyp mit dem
[ValidatableType]Attribut.
Ohne die vorstehenden Schritte zu befolgen, beinhaltet das Verhalten der Formularüberprüfung nicht die Überprüfung von verschachtelten Modellen und Sammlungstypen.
Im folgenden Beispiel werden Kundenbestellungen mit der verbesserten Formularüberprüfung veranschaulicht (Details, die aus Platzgründen weggelassen werden):
Rufen Sie in Program.csder Dienstsammlung folgendes auf AddValidation:
builder.Services.AddValidation();
In der folgenden Order Klasse ist das [ValidatableType] Attribut für den Modelltyp der obersten Ebene erforderlich. Die anderen Typen werden automatisch ermittelt.
OrderItem und ShippingAddress werden nicht aus Platzgründen angezeigt, aber die Validierung bei geschachtelten und Sammlungstypen funktioniert auf dieselbe Weise, wenn sie angezeigt würden.
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 der folgenden OrderPage Komponente ist die DataAnnotationsValidator Komponente in der EditForm Komponente vorhanden.
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();
}
Die Anforderung, die Modelltypen außerhalb von Razor Komponenten (.razor Dateien) zu deklarieren, liegt daran, dass sowohl das neue Überprüfungsfeature als auch der Razor Compiler selbst einen Quellgenerator verwenden. Derzeit kann die Ausgabe eines Quellgenerators nicht als Eingabe für einen anderen Quellgenerator verwendet werden.
Anleitungen zur Verwendung von Validierungsmodellen aus einer anderen Assembly finden Sie unter " Verwenden von Validierungsmodellen aus einem anderen Assemblyabschnitt ".
Geschachtelte Objekte, Sammlungstypen und komplexe Typen
Hinweis
Für Apps für .NET 10 oder höher wird die Verwendung des Microsoft.AspNetCore.Components.DataAnnotations.Validation Pakets und des in diesem Abschnitt beschriebenen Ansatzes nicht mehr empfohlen. Es wird empfohlen, die integrierten Überprüfungsfeatures der DataAnnotationsValidator Komponente zu verwenden.
Blazor bietet Unterstützung für die Validierung von Formulareingaben mithilfe von Datenanmerkungen mit dem integrierten DataAnnotationsValidator. DataAnnotationsValidator In .NET 9 oder früheren Versionen werden jedoch nur Eigenschaften der obersten Ebene des Modells überprüft, die an das Formular gebunden sind, das keine Auflistungs- oder komplexen Eigenschaften enthält.
Verwenden Sie zum Überprüfen des gesamten Objektdiagramms des gebundenen Modells, einschließlich Sammlungs- und komplexen Typeigenschaften, das ObjectGraphDataAnnotationsValidator vom experimentellenMicrosoft.AspNetCore.Components.DataAnnotations.Validation Paket in .NET 9 oder einer früheren Version bereitgestellt wird:
<EditForm ...>
<ObjectGraphDataAnnotationsValidator />
...
</EditForm>
Annotieren Sie Modelleigenschaften mit [ValidateComplexType]. In den folgenden Modellklassen enthält die ShipDescription-Klasse zusätzliche Datenanmerkungen für die Validierung, wenn das Modell an das Formular gebunden ist:
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; }
}
Verwenden von Validierungsmodellen aus einer anderen Assembly
Für die Modellüberprüfung, die in einer anderen Assembly definiert ist, z. B. eine Bibliothek oder das .Client Projekt eines Blazor Web App:
- Wenn es sich bei der Bibliothek um eine einfache Klassenbibliothek handelt (sie basiert nicht auf den
Microsoft.NET.Sdk.WebOderMicrosoft.NET.Sdk.RazorSDKs), fügen Sie einen Paketverweis auf die Bibliothek für dasMicrosoft.Extensions.ValidationNuGet-Paket hinzu. Zusätzliche Schritte sind für einfache Klassenbibliotheken erforderlich, die weiter unten in diesem Abschnitt beschrieben werden. - Erstellen Sie eine Methode in der Bibliothek oder
.Clientim Projekt, die eine IServiceCollection Instanz als Argument empfängt und AddValidation aufruft. - Rufen Sie in der App sowohl die Methode als auch AddValidation auf.
Der vorhergehende Ansatz führt zur Überprüfung der Typen aus beiden Assemblys.
Im folgenden Beispiel wird die AddValidationForTypesInClient Methode für das .Client-Projekt eines Blazor Web App zur Überprüfung mithilfe von Typen erstellt, die im .Client Projekt definiert sind.
ServiceCollectionExtensions.cs (im .Client Projekt):
namespace BlazorSample.Client.Extensions;
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddValidationForTypesInClient(
this IServiceCollection collection)
{
return collection.AddValidation();
}
}
Fügen Sie in der Datei des Serverprojekts Program den Namespace hinzu, und rufen Sie die Dienstsammlungserweiterungsmethode .Client des AddValidationForTypesInClient-Projekts auf und AddValidation.
using BlazorSample.Client.Extensions;
...
builder.Services.AddValidationForTypesInClient();
builder.Services.AddValidation();
Die neuen Attribute aus dem Microsoft.Extensions.Validation Paket (ValidatableTypeAttribute und SkipValidationAttribute) werden als experimentell in .NET 10 veröffentlicht. Das Paket soll eine neue freigegebene Infrastruktur für Validierungsfeatures über Frameworks hinweg bereitstellen, und experimentelle Veröffentlichungstypen bieten eine größere Flexibilität für den endgültigen Entwurf der öffentlichen API für eine bessere Unterstützung bei der Nutzung von Frameworks.
In Blazor Apps werden Typen über ein generiertes eingebettetes Attribut verfügbar gemacht. Wenn ein Web-App-Projekt, das das Microsoft.NET.Sdk.Web SDK (<Project Sdk="Microsoft.NET.Sdk.Web">) oder eine RCL verwendet, die das Microsoft.NET.Sdk.Razor SDK (<Project Sdk="Microsoft.NET.Sdk.Razor">) verwendet, Komponenten (Razor) enthält.razor, generiert das Framework automatisch ein internes Attribut innerhalb des Projekts (Microsoft.Extensions.Validation.Embedded.ValidatableType, Microsoft.Extensions.Validation.Embedded.SkipValidation). Diese Typen sind mit den tatsächlichen Attributen austauschbar und nicht als experimentell markiert. In den meisten Fällen verwenden Entwickler die [ValidatableType]/[SkipValidation] Attribute für ihre Klassen, ohne ihre Quelle zu bedenken.
Der vorherige Ansatz ist jedoch in einfachen Klassenbibliotheken, die das Microsoft.NET.Sdk SDK (<Project Sdk="Microsoft.NET.Sdk">) verwenden, nicht praktikabel. Die Verwendung der Typen in einer einfachen Klassenbibliothek führt zu einer Codeanalysewarnung:
ASP0029: "Microsoft.Extensions.Validation.ValidatableTypeAttribute" dient nur zu Auswertungszwecken und unterliegt Änderungen oder Entfernungen in zukünftigen Updates. Unterdrücken Sie diese Diagnose, um fortzufahren.
Die Warnung kann mit einem der folgenden Ansätze unterdrückt werden:
Eine
<NoWarn>Eigenschaft in der Projektdatei:<PropertyGroup> <NoWarn>$(NoWarn);ASP0029</NoWarn> </PropertyGroup>Eine
pragmaDirektive , in der das Attribut verwendet wird:#pragma warning disable ASP0029 [Microsoft.Extensions.Validation.ValidatableType] #pragma warning restore ASP0029Eine EditorConfig-Dateiregel (
.editorconfig)dotnet_diagnostic.ASP0029.severity = none
Wenn das Unterdrücken der Warnung nicht akzeptabel ist, erstellen Sie manuell das eingebettete Attribut in der Bibliothek, die die Web- und Razor SDKs automatisch generieren.
ValidatableTypeAttribute.cs:
namespace Microsoft.Extensions.Validation.Embedded
{
[AttributeUsage(AttributeTargets.Class)]
internal sealed class ValidatableTypeAttribute : Attribute
{
}
}
Verwenden Sie den genauen Namespace (Microsoft.Extensions.Validation.Embedded) und den Klassennamen (ValidatableTypeAttribute) für den Überprüfungsquellengenerator, um den Typ zu erkennen und zu verwenden. Sie können eine globale using Anweisung für den Namespace deklarieren, entweder mit einer global using Microsoft.Extensions.Validation.Embedded; Anweisung oder mit einem <Using Include="Microsoft.Extensions.Validation.Embedded" /> Element in der Projektdatei der Bibliothek.
Je nachdem, welcher Ansatz angenommen wird, geben Sie an, dass die Problemumgehung für ein zukünftiges Update auf Ihren Code vorhanden ist. Framework-Updates zur Vereinfachung der Einführung von Validierungstypen in einfachen Klassenbibliotheken sind für .NET 11 (November 2026) geplant.
Aktivieren der Schaltfläche zum Senden basierend auf der Formularvalidierung
Um die Senden-Schaltfläche basierend auf der Formularvalidierung zu aktivieren oder zu deaktivieren, verwenden Sie das folgende Beispiel:
- Verwendet eine gekürzte Version des obigen
Starfleet Starship Database-Formulars (Starship3-Komponente) aus dem Abschnitt Beispielformular im Artikel Eingabekomponenten, der nur einen Wert für die ID des Raumfahrzeugs akzeptiert. Die anderenStarship-Eigenschaften erhalten gültige Standardwerte, wenn eine Instanz desStarship-Typs erstellt wird. - Es verwendet den EditContext des Formulars, um das Modell zuzuweisen, wenn die Komponente initialisiert wird.
- Es validiert das Formular im OnFieldChanged-Rückruf des Kontexts, um die Schaltfläche zum Senden zu aktivieren oder zu deaktivieren.
- Implementiert IDisposable und beendet das Abonnement des Ereignishandlers in der
Dispose-Methode. Weitere Informationen finden Sie unter ASP.NET Core Razor Komponentenentsorgung.
Hinweis
Weisen Sie bei der Zuweisung zu EditForm.EditContext nicht auch EditForm.Model dem EditForm zu.
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;
}
}
}
Wenn ein Formular nicht mit gültigen Werten vorab geladen wird und Sie die Schaltfläche Submit beim Laden des Formulars deaktivieren möchten, legen Sie formInvalid auf true fest.
Eine Nebenwirkung des vorangehenden Ansatzes ist, dass eine Validierungszusammenfassung (ValidationSummary-Komponente) mit ungültigen Feldern aufgefüllt wird, nachdem der Benutzer mit einem beliebigen Feld interagiert hat. Behandeln Sie dieses Szenario auf eine der folgenden Arten:
- Verwenden Sie keine ValidationSummary-Komponente des Formulars.
- Lassen Sie die ValidationSummary-Komponente einblenden, wenn auf die Schaltfläche zum Senden geklickt wird, z. B. in einer
Submit-Methode.
<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 Überprüfungsverhalten
Die DataAnnotationsValidator Komponente weist die gleiche Gültigkeitsprüfungsreihenfolge und das Kurzschlussverhalten auf wie System.ComponentModel.DataAnnotations.Validator. Die folgenden Regeln werden beim Überprüfen einer Instanz des Typs Tangewendet:
- Membereigenschaften
Twerden überprüft, einschließlich rekursiv überprüfter geschachtelter Objekte. - Attribute
Tauf Typebene werden überprüft. - Die IValidatableObject.Validate Methode wird ausgeführt, wenn
Tsie implementiert wird.
Wenn einer der vorstehenden Schritte einen Überprüfungsfehler erzeugt, werden die verbleibenden Schritte übersprungen.
ASP.NET Core