ASP.NET Core Blazor form doğrulaması
Uyarı
ASP.NET Core'un bu sürümü artık desteklenmiyor. Daha fazla bilgi için bkz . .NET ve .NET Core Destek İlkesi. Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.
Bu makalede, formlarda Blazor doğrulamanın nasıl kullanılacağı açıklanmaktadır.
Form doğrulama
Temel form doğrulama senaryolarında, bir EditForm örnek form alanlarını doğrulamak için bildirilen EditContext ve ValidationMessageStore örnekleri kullanabilir. olayının OnValidationRequested işleyicisi EditContext özel doğrulama mantığını yürütür. İşleyicinin sonucu örneği güncelleştirir ValidationMessageStore .
Temel form doğrulaması, formun modelinin formu barındıran bileşende doğrudan bileşende veya bir alt sınıfta üye olarak tanımlandığı durumlarda kullanışlıdır. Bağımsız bir model sınıfının çeşitli bileşenler arasında kullanıldığı durumlarda doğrulayıcı bileşeni kullanılması önerilir.
s'de Blazor Web App, istemci tarafı doğrulama için etkin BlazorSignalR bir bağlantı hattı gerekir. İstemci tarafı doğrulaması, statik sunucu tarafı işlemeyi (statik SSR) benimseyen bileşenlerdeki formlar için kullanılamaz. Statik SSR'yi benimseyen formlar, form gönderildikten sonra sunucuda doğrulanır.
Aşağıdaki bileşende HandleValidationRequested
işleyici yöntemi, formu doğrulamadan önce çağırarak ValidationMessageStore.Clear mevcut doğrulama iletilerini temizler.
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;
}
}
}
Veri Ek Açıklamaları Doğrulayıcı bileşeni ve özel doğrulama
Bileşen, DataAnnotationsValidator basamaklı EditContextbir öğesine veri ek açıklamaları doğrulaması ekler. Veri ek açıklama doğrulamasını etkinleştirmek için bileşen gerekir DataAnnotationsValidator . Veri ek açıklamalarından farklı bir doğrulama sistemi kullanmak için bileşen yerine DataAnnotationsValidator özel bir uygulama kullanın. için DataAnnotationsValidator çerçeve uygulamaları, başvuru kaynağında inceleme için kullanılabilir:
Not
.NET başvuru kaynağına yönelik belge bağlantıları genellikle deponun varsayılan dalını yükler ve bu dal .NET'in sonraki sürümü için geçerli geliştirmeyi temsil eder. Belirli bir sürümün etiketini seçmek için Dalları veya etiketleri değiştir açılan listesini kullanın. Daha fazla bilgi için bkz. ASP.NET Core kaynak kodunun sürüm etiketini seçme (dotnet/AspNetCore.Docs #26205).
Blazor iki tür doğrulama gerçekleştirir:
- Alan doğrulaması , kullanıcı bir alanın dışına çıktığında gerçekleştirilir. Alan doğrulama sırasında bileşen, DataAnnotationsValidator bildirilen tüm doğrulama sonuçlarını alanla ilişkilendirir.
- Kullanıcı formu gönderdiğinde model doğrulaması gerçekleştirilir. Model doğrulama sırasında bileşen, DataAnnotationsValidator doğrulama sonucunun rapor verdiği üye adına göre alanı belirlemeye çalışır. Tek bir üyeyle ilişkilendirilmeyen doğrulama sonuçları alan yerine modelle ilişkilendirilir.
Doğrulayıcı bileşenleri
Doğrulayıcı bileşenleri, formun için öğesini ValidationMessageStore yöneterek form EditContextdoğrulamasını destekler.
Çerçeve, Blazor doğrulama özniteliklerine DataAnnotationsValidator (veri ek açıklamaları) göre formlara doğrulama desteği eklemek için bileşen sağlar. Farklı form işleme adımlarında (örneğin, istemci doğrulamasının ardından sunucu doğrulaması) aynı sayfada veya aynı formda farklı formlar için doğrulama iletilerini işlemek için özel doğrulayıcı bileşenleri oluşturabilirsiniz. Bu bölümde gösterilen doğrulayıcı bileşeni örneği, CustomValidation
bu makalenin aşağıdaki bölümlerinde kullanılır:
Yerleşik veri ek açıklaması doğrulayıcıları içinde yalnızca [Remote]
doğrulama özniteliği desteklenmezBlazor.
Not
Birçok durumda özel doğrulayıcı bileşenleri yerine özel veri ek açıklaması doğrulama öznitelikleri kullanılabilir. Formun modeline uygulanan özel öznitelikler, bileşenin DataAnnotationsValidator kullanımıyla etkinleştirilir. Sunucu doğrulaması ile kullanıldığında, modele uygulanan tüm özel özniteliklerin sunucuda yürütülebilir olması gerekir. Daha fazla bilgi için Özel doğrulama öznitelikleri bölümüne bakın.
adresinden ComponentBasebir doğrulayıcı bileşeni oluşturun:
- Formunki EditContext , bileşenin basamaklı bir parametresidir .
- Doğrulayıcı bileşeni başlatıldığında, form hatalarının geçerli listesini korumak için yeni ValidationMessageStore bir oluşturulur.
- Formun bileşenindeki geliştirici kodu yöntemini çağırdığında
DisplayErrors
ileti deposu hata alır. Hatalar içindekiDictionary<string, List<string>>
yöntemineDisplayErrors
geçirilir. Sözlükte anahtar, bir veya daha fazla hatası olan form alanının adıdır. Değer hata listesidir. - Aşağıdakilerden herhangi biri oluştuğunda iletiler temizlenir:
- Olay tetiklendiğinde OnValidationRequested doğrulama EditContext istenir. Tüm hatalar temizlenir.
- Olay tetiklendiğinde OnFieldChanged formda bir alan değişir. Yalnızca alanın hataları temizlenir.
ClearErrors
yöntemi geliştirici kodu tarafından çağrılır. Tüm hatalar temizlenir.
Aşağıdaki sınıftaki ad alanını uygulamanızın ad alanıyla eşleşecek şekilde güncelleştirin.
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();
}
}
Önemli
'den ComponentBasetüretilirken ad alanı belirtmek gerekir. Ad alanı belirtilememek derleme hatasıyla sonuçlanır:
Tag helpers cannot target tag name '<global namespace>.{CLASS NAME}' because it contains a ' ' character.
Yer {CLASS NAME}
tutucu, bileşen sınıfının adıdır. Bu bölümdeki özel doğrulayıcı örneği, örnek ad alanını BlazorSample
belirtir.
Not
Anonim lambda ifadeleri, önceki örnekte ve OnFieldChanged için OnValidationRequested kayıtlı olay işleyicileridir. Bu senaryoda olay temsilcilerinin uygulanması IDisposable ve aboneliğinin kaldırılması gerekmez. Daha fazla bilgi için bkz. ASP.NET Core Razor bileşeni yaşam döngüsü.
Doğrulayıcı bileşeniyle iş mantığı doğrulaması
Genel iş mantığı doğrulaması için, bir sözlükte form hataları alan bir doğrulayıcı bileşeni kullanın.
Temel doğrulama, formun modelinin, doğrudan bileşende veya bir alt sınıfta üye olarak formu barındıran bileşen içinde tanımlandığı durumlarda kullanışlıdır. Bağımsız bir model sınıfının çeşitli bileşenler arasında kullanıldığı durumlarda doğrulayıcı bileşeni kullanılması önerilir.
Aşağıdaki örnekte:
- Giriş bileşenleri makalesinin
Starfleet Starship Database
Örnek form bölümünün formun (Starship3
bileşen) kısaltılmış bir sürümü, yalnızca yıldızgeminin sınıflandırmasını ve açıklamasını kabul eden kullanılır. Bileşen forma dahil edilmediğinden DataAnnotationsValidator , form gönderiminde veri ek açıklaması doğrulaması tetiklenmez. - Bu
CustomValidation
makalenin Validator bileşenleri bölümünde yer alan bileşen kullanılır. - Doğrulama, kullanıcı "
Defense
" gemi sınıflandırmasını (Description
) seçerse, geminin açıklaması (Classification
) için bir değer gerektirir.
Bileşende doğrulama iletileri ayarlandığında, bunlar doğrulayıcıya ValidationMessageStore eklenir ve 'nin doğrulama özetinde EditFormgösterilir.
Starship9.razor
:
@page "/starship-9"
@inject ILogger<Starship9> Logger
<h1>Starfleet Starship Database</h1>
<h2>New Ship Entry Form</h2>
<EditForm Model="Model" OnValidSubmit="Submit" FormName="Starship9">
<CustomValidation @ref="customValidation" />
<ValidationSummary />
<div>
<label>
Primary Classification:
<InputSelect @bind-Value="Model!.Classification">
<option value="">
Select classification ...
</option>
<option checked="@(Model!.Classification == "Exploration")"
value="Exploration">
Exploration
</option>
<option checked="@(Model!.Classification == "Diplomacy")"
value="Diplomacy">
Diplomacy
</option>
<option checked="@(Model!.Classification == "Defense")"
value="Defense">
Defense
</option>
</InputSelect>
</label>
</div>
<div>
<label>
Description (optional):
<InputTextArea @bind-Value="Model!.Description" />
</label>
</div>
<div>
<button type="submit">Submit</button>
</div>
</EditForm>
@code {
private CustomValidation? customValidation;
[SupplyParameterFromForm]
private Starship? Model { get; set; }
protected override void OnInitialized() =>
Model ??= new() { ProductionDate = DateTime.UtcNow };
private void Submit()
{
customValidation?.ClearErrors();
var errors = new Dictionary<string, List<string>>();
if (Model!.Classification == "Defense" &&
string.IsNullOrEmpty(Model.Description))
{
errors.Add(nameof(Model.Description),
new() { "For a 'Defense' ship classification, " +
"'Description' is required." });
}
if (errors.Any())
{
customValidation?.DisplayErrors(errors);
}
else
{
Logger.LogInformation("Submit called: Processing the form");
}
}
}
@page "/starship-9"
@inject ILogger<Starship9> Logger
<h1>Starfleet Starship Database</h1>
<h2>New Ship Entry Form</h2>
<EditForm Model="Model" OnValidSubmit="Submit" FormName="Starship9">
<CustomValidation @ref="customValidation" />
<ValidationSummary />
<div>
<label>
Primary Classification:
<InputSelect @bind-Value="Model!.Classification">
<option value="">
Select classification ...
</option>
<option checked="@(Model!.Classification == "Exploration")"
value="Exploration">
Exploration
</option>
<option checked="@(Model!.Classification == "Diplomacy")"
value="Diplomacy">
Diplomacy
</option>
<option checked="@(Model!.Classification == "Defense")"
value="Defense">
Defense
</option>
</InputSelect>
</label>
</div>
<div>
<label>
Description (optional):
<InputTextArea @bind-Value="Model!.Description" />
</label>
</div>
<div>
<button type="submit">Submit</button>
</div>
</EditForm>
@code {
private CustomValidation? customValidation;
[SupplyParameterFromForm]
private Starship? Model { get; set; }
protected override void OnInitialized() =>
Model ??= new() { ProductionDate = DateTime.UtcNow };
private void Submit()
{
customValidation?.ClearErrors();
var errors = new Dictionary<string, List<string>>();
if (Model!.Classification == "Defense" &&
string.IsNullOrEmpty(Model.Description))
{
errors.Add(nameof(Model.Description),
new() { "For a 'Defense' ship classification, " +
"'Description' is required." });
}
if (errors.Any())
{
customValidation?.DisplayErrors(errors);
}
else
{
Logger.LogInformation("Submit called: Processing the form");
}
}
}
@page "/starship-9"
@inject ILogger<Starship9> Logger
<h1>Starfleet Starship Database</h1>
<h2>New Ship Entry Form</h2>
<EditForm Model="Model" OnValidSubmit="Submit">
<CustomValidation @ref="customValidation" />
<ValidationSummary />
<div>
<label>
Primary Classification:
<InputSelect @bind-Value="Model!.Classification">
<option value="">Select classification ...</option>
<option value="Exploration">Exploration</option>
<option value="Diplomacy">Diplomacy</option>
<option value="Defense">Defense</option>
</InputSelect>
</label>
</div>
<div>
<label>
Description (optional):
<InputTextArea @bind-Value="Model!.Description" />
</label>
</div>
<div>
<button type="submit">Submit</button>
</div>
</EditForm>
@code {
private CustomValidation? customValidation;
public Starship? Model { get; set; }
protected override void OnInitialized() =>
Model ??= new() { ProductionDate = DateTime.UtcNow };
private void Submit()
{
customValidation?.ClearErrors();
var errors = new Dictionary<string, List<string>>();
if (Model!.Classification == "Defense" &&
string.IsNullOrEmpty(Model.Description))
{
errors.Add(nameof(Model.Description),
new() { "For a 'Defense' ship classification, " +
"'Description' is required." });
}
if (errors.Any())
{
customValidation?.DisplayErrors(errors);
}
else
{
Logger.LogInformation("Submit called: Processing the form");
}
}
}
Not
Doğrulama bileşenlerini kullanmaya alternatif olarak, veri ek açıklaması doğrulama öznitelikleri kullanılabilir. Formun modeline uygulanan özel öznitelikler, bileşenin DataAnnotationsValidator kullanımıyla etkinleştirilir. Sunucu doğrulaması ile kullanıldığında özniteliklerin sunucuda yürütülebilir olması gerekir. Daha fazla bilgi için Özel doğrulama öznitelikleri bölümüne bakın.
Doğrulayıcı bileşeniyle sunucu doğrulaması
Bu bölüm senaryolara odaklanmıştır Blazor Web App ancak web API'siyle sunucu doğrulaması kullanan her tür uygulama için yaklaşım aynı genel yaklaşımı benimser.
Bu bölüm barındırılan Blazor WebAssembly senaryolara odaklanmıştır, ancak web API'siyle sunucu doğrulaması kullanan her tür uygulama için yaklaşım aynı genel yaklaşımı benimser.
sunucu doğrulaması, istemci doğrulamasına ek olarak desteklenir:
- formdaki istemci doğrulamasını bileşenle birlikte işleyin DataAnnotationsValidator .
- Form istemci doğrulamasını (OnValidSubmit çağrılır) geçtiğinde EditContext.Model , form işleme için bir arka uç sunucu API'sine gönderin.
- Sunucuda model doğrulama işlemini gerçekleştirme.
- Sunucu API'sinde hem yerleşik çerçeve veri ek açıklamaları doğrulaması hem de geliştirici tarafından sağlanan özel doğrulama mantığı bulunur. Doğrulama sunucudan geçerse formu işleyin ve bir başarı durumu kodu (
200 - OK
) geri gönderin. Doğrulama başarısız olursa, bir hata durum kodu (400 - Bad Request
) ve alan doğrulama hataları döndürür. - Formu başarılı olduğunda devre dışı bırakın veya hataları görüntüleyin.
Temel doğrulama, formun modelinin, doğrudan bileşende veya bir alt sınıfta üye olarak formu barındıran bileşen içinde tanımlandığı durumlarda kullanışlıdır. Bağımsız bir model sınıfının çeşitli bileşenler arasında kullanıldığı durumlarda doğrulayıcı bileşeni kullanılması önerilir.
Aşağıdaki örnek aşağıdakileri temel alır:
- Blazor Web App Proje şablonundan oluşturulan Etkileşimli WebAssembly bileşenlerine sahip ABlazor Web App.
Starship
Giriş bileşenleri makalesinin Örnek form bölümünün modeli (Starship.cs
).CustomValidation
Doğrulayıcı bileşenleri bölümünde gösterilen bileşen.
Starship
Hem istemci hem de sunucu projelerinin modeli kullanabilmesi için modeli (Starship.cs
) paylaşılan bir sınıf kitaplığı projesine yerleştirin. Ad alanını paylaşılan uygulamanın ad alanıyla eşleşecek şekilde ekleyin veya güncelleştirin (örneğin, namespace BlazorSample.Shared
). Model veri ek açıklamaları gerektirdiğinden, paylaşılan sınıf kitaplığının paylaşılan çerçeveyi kullandığını onaylayın veya paketi paylaşılan projeye ekleyin System.ComponentModel.Annotations
.
Not
.NET uygulamalarına paket ekleme hakkında yönergeler için, Paket tüketimi iş akışında (NuGet belgeleri) paketleri yüklemek ve yönetmek altındaki makalelere bakın. NuGet.org'da doğru paket sürümlerini onaylayın.
ana projesinde Blazor Web App, yıldız gemisi doğrulama isteklerini işlemek ve başarısız doğrulama iletilerini döndürmek için bir denetleyici ekleyin. Paylaşılan sınıf kitaplığı projesi ve denetleyici sınıfı için son using
deyimdeki namespace
ad alanlarını güncelleştirin. İstemci ve sunucu veri ek açıklamaları doğrulamasına ek olarak, kullanıcı gemi sınıflandırmasınıClassification
() seçerse denetleyici, geminin açıklaması (Description
) için bir değer sağlandığını doğrularDefense
.
- Proje şablonundan oluşturulan barındırılan Blazor WebAssemblyBlazor WebAssemblybir çözüm. Bu yaklaşım, barındırılan Blazor WebAssembly güvenlik belgelerinde açıklanan güvenli barındırılan Blazor çözümlerden herhangi biri için desteklenir.
Starship
Giriş bileşenleri makalesinin Örnek form bölümünün modeli (Starship.cs
).CustomValidation
Doğrulayıcı bileşenleri bölümünde gösterilen bileşen.
Starship
Hem istemci hem de sunucu uygulamalarının modeli kullanabilmesi Shared
için modeli (Starship.cs
) çözümün projesine yerleştirin. Ad alanını paylaşılan uygulamanın ad alanıyla eşleşecek şekilde ekleyin veya güncelleştirin (örneğin, namespace BlazorSample.Shared
). Model için veri ek açıklamaları gerektiğinden System.ComponentModel.Annotations
paketi Shared
projeye ekleyin.
Not
.NET uygulamalarına paket ekleme hakkında yönergeler için, Paket tüketimi iş akışında (NuGet belgeleri) paketleri yüklemek ve yönetmek altındaki makalelere bakın. NuGet.org'da doğru paket sürümlerini onaylayın.
Projede Server , yıldız gemisi doğrulama isteklerini işlemek ve başarısız doğrulama iletilerini döndürmek için bir denetleyici ekleyin. Projenin namespace
ve denetleyici sınıfının son using
deyimindeki Shared
ad alanlarını güncelleştirin. İstemci ve sunucu veri ek açıklamaları doğrulamasına ek olarak, kullanıcı gemi sınıflandırmasınıClassification
() seçerse denetleyici, geminin açıklaması (Description
) için bir değer sağlandığını doğrularDefense
.
Yaklaşan form sunucuya gönderildiğinde aynı doğrulama istemci tarafını gerçekleştirmediğinden, gemi sınıflandırması için doğrulama Defense
yalnızca denetleyicideki sunucuda gerçekleşir. İstemci doğrulaması olmadan sunucu doğrulaması, sunucudaki kullanıcı girişinin özel iş mantığı doğrulaması gerektiren uygulamalarda yaygındır. Örneğin, kullanıcı girişini doğrulamak için bir kullanıcı için depolanan verilerden özel bilgiler gerekebilir. Özel veriler açıkça istemci doğrulaması için istemciye gönderilemiyor.
Not
StarshipValidation
Bu bölümdeki denetleyici Microsoft Identity 2.0 kullanır. Web API'si yalnızca bu API için "API.Access
" kapsamına sahip kullanıcılar için belirteçleri kabul eder. API'nin kapsam adı ile API.Access
farklıysa ek özelleştirme gerekir.
Güvenlik hakkında daha fazla bilgi için bkz:
- ASP.NET Çekirdek Blazor kimlik doğrulaması ve yetkilendirme (ve Güvenlik ve Identity düğümdeki Blazordiğer makaleler)
- Microsoft identity platformu belgeleri
Controllers/StarshipValidation.cs
:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using BlazorSample.Shared;
namespace BlazorSample.Server.Controllers;
[Authorize]
[ApiController]
[Route("[controller]")]
public class StarshipValidationController(
ILogger<StarshipValidationController> logger)
: ControllerBase
{
static readonly string[] scopeRequiredByApi = new[] { "API.Access" };
[HttpPost]
public async Task<IActionResult> Post(Starship model)
{
HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
try
{
if (model.Classification == "Defense" &&
string.IsNullOrEmpty(model.Description))
{
ModelState.AddModelError(nameof(model.Description),
"For a 'Defense' ship " +
"classification, 'Description' is required.");
}
else
{
logger.LogInformation("Processing the form asynchronously");
// async ...
return Ok(ModelState);
}
}
catch (Exception ex)
{
logger.LogError("Validation Error: {Message}", ex.Message);
}
return BadRequest(ModelState);
}
}
Önceki denetleyicinin (BlazorSample.Server.Controllers
) ad alanını, uygulamanın denetleyicilerinin ad alanıyla eşleşecek şekilde onaylayın veya güncelleştirin.
Sunucuda model bağlama doğrulama hatası oluştuğunda, ApiController
(ApiControllerAttribute) normalde ile ValidationProblemDetailsvarsayılan bir hatalı istek yanıtı döndürür. Aşağıdaki örnekte gösterildiği gibi, formun tüm alanları gönderilmediğinde ve form doğrulamada başarısız olduğunda yanıt yalnızca doğrulama hatalarından Starfleet Starship Database
daha fazla veri içerir:
{
"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)."]
}
}
Not
Yukarıdaki JSON yanıtını göstermek için formun istemci doğrulamasını devre dışı bırakarak boş alan formu göndermeye izin vermelisiniz veya Firefox Browser Developer gibi sunucu API'sine doğrudan istek göndermek için bir araç kullanmalısınız.
Sunucu API'si önceki varsayılan JSON yanıtını döndürürse istemcinin yanıtı geliştirici kodunda ayrıştırarak form doğrulama hatası işleme için düğümün errors
alt öğelerini alması mümkündür. Dosyayı ayrıştırmak için geliştirici kodu yazmak uygun değildir. JSON'un el ile ayrıştırılması, çağrıldıktan ReadFromJsonAsyncsonra hata Dictionary<string, List<string>>
üretmeyi gerektirir. İdeal olarak, aşağıdaki örnekte gösterildiği gibi sunucu API'sinin yalnızca doğrulama hatalarını döndürmesi gerekir:
{
"Id": ["The Id field is required."],
"Classification": ["The Classification field is required."],
"IsValidatedDesign": ["This form disallows unapproved ships."],
"MaximumAccommodation": ["Accommodation invalid (1-100000)."]
}
Sunucu API'sinin yanıtını yalnızca doğrulama hatalarını döndürecek şekilde değiştirmek için, dosyada ek açıklama ApiControllerAttribute eklenmiş eylemlerde çağrılan temsilciyi Program
değiştirin. API uç noktası ()/StarshipValidation
için ile bir BadRequestObjectResult ModelStateDictionarydöndürür. Diğer TÜM API uç noktaları için nesne sonucunu yeni ValidationProblemDetailsbir ile döndürerek varsayılan davranışı koruyun.
ad alanını Microsoft.AspNetCore.Mvc dosyasının Program
ana projesindeki Blazor Web Appdosyanın en üstüne ekleyin:
using Microsoft.AspNetCore.Mvc;
Program
dosyasında, aşağıdaki AddControllersWithViews uzantı yöntemini ekleyin veya güncelleştirin ve öğesine aşağıdaki çağrıyı ConfigureApiBehaviorOptionsekleyin:
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));
}
};
});
denetleyicilerini ilk kez ana projesine Blazor Web App ekliyorsanız, denetleyiciler için hizmetleri kaydeden önceki kodu yerleştirdiğinizde denetleyici uç noktalarını eşleyin. Aşağıdaki örnek varsayılan denetleyici yollarını kullanır:
app.MapDefaultControllerRoute();
Not
Yukarıdaki örnek, Siteler Arası İstek Sahteciliği (XSRF/CSRF) saldırılarını otomatik olarak azaltmak için çağırarak AddControllersWithViews denetleyici hizmetlerini açıkça kaydeder. Yalnızca kullanıyorsanız AddControllers, kötü amaçlı yazılımdan koruma otomatik olarak etkinleştirilmez.
Denetleyici yönlendirme ve doğrulama hatası hata yanıtları hakkında daha fazla bilgi için aşağıdaki kaynaklara bakın:
- ASP.NET Core'de denetleyici eylemlerine yönlendirme
- ASP.NET Core denetleyici tabanlı web API'lerindeki hataları işleme
Projede.Client
, Doğrulayıcı bileşenleri bölümünde gösterilen bileşeni ekleyinCustomValidation
. Ad alanını uygulamayla eşleşecek şekilde güncelleştirin (örneğin, namespace BlazorSample.Client
).
Projede .Client
, form bileşenin Starfleet Starship Database
yardımıyla CustomValidation
sunucu doğrulama hatalarını gösterecek şekilde güncelleştirilir. Sunucu API'sinin doğrulama iletileri döndürdüğünde, bunlar bileşenin CustomValidation
ValidationMessageStoreöğesine eklenir. Hatalar formun EditContext doğrulama özetinde görüntülenmek üzere formlarda kullanılabilir.
Aşağıdaki bileşende, paylaşılan projenin ad alanını (@using BlazorSample.Shared
) paylaşılan projenin ad alanına güncelleştirin. Formun yetkilendirme gerektirdiğini, bu nedenle kullanıcının forma gitmek için uygulamada oturum açması gerektiğini unutmayın.
Ad alanını Microsoft.AspNetCore.Mvc uygulamadaki dosyanın Server en üstüne Program
ekleyin:
using Microsoft.AspNetCore.Mvc;
Program
dosyasında uzantı yöntemini bulun AddControllersWithViews ve öğesine aşağıdaki çağrıyı ConfigureApiBehaviorOptionsekleyin:
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));
}
};
});
Not
Yukarıdaki örnek, Siteler Arası İstek Sahteciliği (XSRF/CSRF) saldırılarını otomatik olarak azaltmak için çağırarak AddControllersWithViews denetleyici hizmetlerini açıkça kaydeder. Yalnızca kullanıyorsanız AddControllers, kötü amaçlı yazılımdan koruma otomatik olarak etkinleştirilmez.
ProjedeClient, Doğrulayıcı bileşenleri bölümünde gösterilen bileşeni ekleyinCustomValidation
. Ad alanını uygulamayla eşleşecek şekilde güncelleştirin (örneğin, namespace BlazorSample.Client
).
Projede Client , form bileşenin Starfleet Starship Database
yardımıyla CustomValidation
sunucu doğrulama hatalarını gösterecek şekilde güncelleştirilir. Sunucu API'sinin doğrulama iletileri döndürdüğünde, bunlar bileşenin CustomValidation
ValidationMessageStoreöğesine eklenir. Hatalar formun EditContext doğrulama özetinde görüntülenmek üzere formlarda kullanılabilir.
Aşağıdaki bileşende, projenin ad alanını Shared
(@using BlazorSample.Shared
) paylaşılan projenin ad alanına güncelleştirin. Formun yetkilendirme gerektirdiğini, bu nedenle kullanıcının forma gitmek için uygulamada oturum açması gerektiğini unutmayın.
Starship10.razor
:
Not
Antiforgery desteğini otomatik olarak etkinleştiren EditForm formlar. Denetleyici, denetleyici hizmetlerini kaydetmek ve web API'sine yönelik kötü amaçlı yazılımdan koruma desteğini otomatik olarak etkinleştirmek için kullanmalıdır AddControllersWithViews .
@page "/starship-10"
@rendermode InteractiveWebAssembly
@using System.Net
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using BlazorSample.Shared
@attribute [Authorize]
@inject HttpClient Http
@inject ILogger<Starship10> Logger
<h1>Starfleet Starship Database</h1>
<h2>New Ship Entry Form</h2>
<EditForm FormName="Starship10" Model="Model" OnValidSubmit="Submit">
<DataAnnotationsValidator />
<CustomValidation @ref="customValidation" />
<ValidationSummary />
<div>
<label>
Identifier:
<InputText @bind-Value="Model!.Id" disabled="@disabled" />
</label>
</div>
<div>
<label>
Description (optional):
<InputTextArea @bind-Value="Model!.Description"
disabled="@disabled" />
</label>
</div>
<div>
<label>
Primary Classification:
<InputSelect @bind-Value="Model!.Classification" disabled="@disabled">
<option value="">Select classification ...</option>
<option value="Exploration">Exploration</option>
<option value="Diplomacy">Diplomacy</option>
<option value="Defense">Defense</option>
</InputSelect>
</label>
</div>
<div>
<label>
Maximum Accommodation:
<InputNumber @bind-Value="Model!.MaximumAccommodation"
disabled="@disabled" />
</label>
</div>
<div>
<label>
Engineering Approval:
<InputCheckbox @bind-Value="Model!.IsValidatedDesign"
disabled="@disabled" />
</label>
</div>
<div>
<label>
Production Date:
<InputDate @bind-Value="Model!.ProductionDate" disabled="@disabled" />
</label>
</div>
<div>
<button type="submit" disabled="@disabled">Submit</button>
</div>
<div style="@messageStyles">
@message
</div>
</EditForm>
@code {
private CustomValidation? customValidation;
private bool disabled;
private string? message;
private string messageStyles = "visibility:hidden";
[SupplyParameterFromForm]
private Starship? Model { get; set; }
protected override void OnInitialized() =>
Model ??= new() { ProductionDate = DateTime.UtcNow };
private async Task Submit(EditContext editContext)
{
customValidation?.ClearErrors();
try
{
var response = await Http.PostAsJsonAsync<Starship>(
"StarshipValidation", (Starship)editContext.Model);
var errors = await response.Content
.ReadFromJsonAsync<Dictionary<string, List<string>>>() ??
new Dictionary<string, List<string>>();
if (response.StatusCode == HttpStatusCode.BadRequest &&
errors.Any())
{
customValidation?.DisplayErrors(errors);
}
else if (!response.IsSuccessStatusCode)
{
throw new HttpRequestException(
$"Validation failed. Status Code: {response.StatusCode}");
}
else
{
disabled = true;
messageStyles = "color:green";
message = "The form has been processed.";
}
}
catch (AccessTokenNotAvailableException ex)
{
ex.Redirect();
}
catch (Exception ex)
{
Logger.LogError("Form processing error: {Message}", ex.Message);
disabled = true;
messageStyles = "color:red";
message = "There was an error processing the form.";
}
}
}
projesinin .Client
Blazor Web App arka uç web API denetleyicisine HTTP POST istekleri için de kaydetmesi HttpClient gerekir. Projenin Program
dosyasına aşağıdakileri .Client
onaylayın veya ekleyin:
builder.Services.AddScoped(sp =>
new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
Yukarıdaki örnek, uygulamanın temel adresini alan ve genellikle ana bilgisayar sayfasındaki etiketin href
değerinden <base>
türetilen temel adresi ()IWebAssemblyHostEnvironment.BaseAddress ile builder.HostEnvironment.BaseAddress
ayarlar.
@page "/starship-10"
@using System.Net
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using BlazorSample.Shared
@attribute [Authorize]
@inject HttpClient Http
@inject ILogger<Starship10> Logger
<h1>Starfleet Starship Database</h1>
<h2>New Ship Entry Form</h2>
<EditForm Model="Model" OnValidSubmit="Submit">
<DataAnnotationsValidator />
<CustomValidation @ref="customValidation" />
<ValidationSummary />
<div>
<label>
Identifier:
<InputText @bind-Value="Model!.Id" disabled="@disabled" />
</label>
</div>
<div>
<label>
Description (optional):
<InputTextArea @bind-Value="Model!.Description"
disabled="@disabled" />
</label>
</div>
<div>
<label>
Primary Classification:
<InputSelect @bind-Value="Model!.Classification" disabled="@disabled">
<option value="">Select classification ...</option>
<option value="Exploration">Exploration</option>
<option value="Diplomacy">Diplomacy</option>
<option value="Defense">Defense</option>
</InputSelect>
</label>
</div>
<div>
<label>
Maximum Accommodation:
<InputNumber @bind-Value="Model!.MaximumAccommodation"
disabled="@disabled" />
</label>
</div>
<div>
<label>
Engineering Approval:
<InputCheckbox @bind-Value="Model!.IsValidatedDesign"
disabled="@disabled" />
</label>
</div>
<div>
<label>
Production Date:
<InputDate @bind-Value="Model!.ProductionDate" disabled="@disabled" />
</label>
</div>
<div>
<button type="submit" disabled="@disabled">Submit</button>
</div>
<div style="@messageStyles">
@message
</div>
</EditForm>
@code {
private CustomValidation? customValidation;
private bool disabled;
private string? message;
private string messageStyles = "visibility:hidden";
public Starship? Model { get; set; }
protected override void OnInitialized() =>
Model ??= new() { ProductionDate = DateTime.UtcNow };
private async Task Submit(EditContext editContext)
{
customValidation?.ClearErrors();
try
{
var response = await Http.PostAsJsonAsync<Starship>(
"StarshipValidation", (Starship)editContext.Model);
var errors = await response.Content
.ReadFromJsonAsync<Dictionary<string, List<string>>>() ??
new Dictionary<string, List<string>>();
if (response.StatusCode == HttpStatusCode.BadRequest &&
errors.Any())
{
customValidation?.DisplayErrors(errors);
}
else if (!response.IsSuccessStatusCode)
{
throw new HttpRequestException(
$"Validation failed. Status Code: {response.StatusCode}");
}
else
{
disabled = true;
messageStyles = "color:green";
message = "The form has been processed.";
}
}
catch (AccessTokenNotAvailableException ex)
{
ex.Redirect();
}
catch (Exception ex)
{
Logger.LogError("Form processing error: {Message}", ex.Message);
disabled = true;
messageStyles = "color:red";
message = "There was an error processing the form.";
}
}
}
Not
Doğrulama bileşeninin kullanımına alternatif olarak, veri ek açıklaması doğrulama öznitelikleri kullanılabilir. Formun modeline uygulanan özel öznitelikler, bileşenin DataAnnotationsValidator kullanımıyla etkinleştirilir. Sunucu doğrulaması ile kullanıldığında özniteliklerin sunucuda yürütülebilir olması gerekir. Daha fazla bilgi için Özel doğrulama öznitelikleri bölümüne bakın.
Not
Bu bölümdeki sunucu doğrulama yaklaşımı, bu belge kümesindeki barındırılan Blazor WebAssembly çözüm örneklerinden herhangi biri için uygundur:
InputText
giriş olayına göre
Bileşeni kullanarak InputText olay () yerine onchange
change
olayı (input
) kullanan oninput
özel bir bileşen oluşturun. input
Olay kullanımı, her tuş vuruşu üzerinde alan doğrulamasını tetikler.
Aşağıdaki CustomInputText
bileşen, çerçevenin InputText
bileşenini devralır ve olay bağlamasını oninput
(input
) ayarlar.
CustomInputText.razor
:
@inherits InputText
<input @attributes="AdditionalAttributes"
class="@CssClass"
@bind="CurrentValueAsString"
@bind:event="oninput" />
Bileşen CustomInputText
her yerde InputText kullanılabilir. Aşağıdaki bileşen paylaşılan CustomInputText
bileşeni kullanır.
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; }
}
}
Doğrulama Özeti ve Doğrulama İletisi bileşenleri
BileşenValidationSummary, Doğrulama Özeti Etiketi Yardımcısı'na benzer tüm doğrulama iletilerini özetler:
<ValidationSummary />
Parametresiyle Model
belirli bir model için çıkış doğrulama iletileri:
<ValidationSummary Model="Model" />
Bileşen, ValidationMessage<TValue> Doğrulama İletisi Etiketi Yardımcısı'na benzeyen belirli bir alanın doğrulama iletilerini görüntüler. özniteliğiyle For doğrulama alanını ve model özelliğini adlandıran bir lambda ifadesi belirtin:
<ValidationMessage For="@(() => Model!.MaximumAccommodation)" />
ValidationMessage<TValue> ve ValidationSummary bileşenleri rastgele öznitelikleri destekler. Bir bileşen parametresiyle eşleşmeyen tüm öznitelikler, oluşturulan <div>
veya <ul>
öğesine eklenir.
Uygulamanın stil sayfasında (wwwroot/css/app.css
veya wwwroot/css/site.css
) doğrulama iletilerinin stilini denetleme. Varsayılan validation-message
sınıf, doğrulama iletilerinin metin rengini kırmızıya ayarlar:
.validation-message {
color: red;
}
Form alanının geçerli olup olmadığını belirleme
Doğrulama iletileri almadan bir alanın geçerli olup olmadığını belirlemek için kullanın EditContext.IsValid .
Desteklenir, ancak önerilmez:
var isValid = !editContext.GetValidationMessages(fieldIdentifier).Any();
Önerilen:
var isValid = editContext.IsValid(fieldIdentifier);
Özel doğrulama öznitelikleri
Bir doğrulama sonucunun özel doğrulama özniteliği kullanılırken bir alanla doğru ilişkilendirildiğinden emin olmak için, öğesini oluştururken doğrulama bağlamını MemberName ValidationResultgeçirin.
CustomValidator.cs
:
using System;
using System.ComponentModel.DataAnnotations;
public class CustomValidator : ValidationAttribute
{
protected override ValidationResult IsValid(object value,
ValidationContext validationContext)
{
...
return new ValidationResult("Validation message to user.",
new[] { validationContext.MemberName });
}
}
aracılığıyla özel doğrulama özniteliklerine hizmet ekleme ValidationContext. Aşağıdaki örnekte, bağımlılık ekleme (DI) ile kullanıcı girişini doğrulayan bir salata şefi formu gösterilmektedir.
Sınıf, SaladChef
On İleri salatası için onaylanmış yıldız gemisi malzeme listesini gösterir.
SaladChef.cs
:
namespace BlazorSample;
public class SaladChef
{
public string[] SaladToppers = { "Horva", "Kanda Root", "Krintar", "Plomeek",
"Syto Bean" };
}
Dosyanın içinde uygulamanın DI kapsayıcısında kaydolun SaladChef
Program
:
builder.Services.AddTransient<SaladChef>();
IsValid
Aşağıdaki SaladChefValidatorAttribute
sınıfın yöntemi, kullanıcının girişini denetlemek için DI'den hizmeti alırSaladChef
.
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));
}
}
Aşağıdaki bileşen, salata bileşen dizesine SaladChefValidatorAttribute
SaladIngredient
([SaladChefValidator]
) uygulayarak kullanıcı girişini doğrular.
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);
}
Özel doğrulama CSS sınıf öznitelikleri
Özel doğrulama CSS sınıfı öznitelikleri, Bootstrap gibi CSS çerçeveleriyle tümleştirme yaparken kullanışlıdır.
Özel doğrulama CSS sınıf özniteliklerini belirtmek için, özel doğrulama için CSS stilleri sağlayarak başlayın. Aşağıdaki örnekte geçerli (validField
) ve geçersiz (invalidField
) stiller belirtilmiştir.
Uygulamanın stil sayfasına aşağıdaki CSS sınıflarını ekleyin:
.validField {
border-color: lawngreen;
}
.invalidField {
background-color: tomato;
}
Alan doğrulama iletilerini denetleyen ve uygun geçerli veya geçersiz stili uygulayan bir FieldCssClassProvider sınıf oluşturun.
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";
}
}
sınıfınıCustomFieldClassProvider
, ile SetFieldCssClassProviderformun EditContext örneğinde Alan CSS Sınıf Sağlayıcısı olarak ayarlayın.
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; }
}
}
Yukarıdaki örnek, tüm form alanlarının geçerliliğini denetler ve her alana bir stil uygular. Formun alanların yalnızca bir alt kümesine özel stiller uygulaması gerekiyorsa, CustomFieldClassProvider
stilleri koşullu olarak uygulayın. Aşağıdaki CustomFieldClassProvider2
örnek alana yalnızca bir stil Name
uygular. adlarıyla eşleşmeyen Name
string.Empty
alanlar için döndürülür ve stil uygulanmaz. Yansıma kullanıldığında, alan, HTML varlığına atanmış değil id
model üyesinin özelliği veya alan adıyla eşleştirilir.
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;
}
}
Not
Önceki örnekte alan adıyla eşleştirme büyük/küçük harfe duyarlıdır, bu nedenle "Name
" olarak belirlenmiş bir model özelliği üyesinin "Name
" üzerindeki koşullu denetimle eşleşmesi gerekir:
- Doğru eşleşmeler:
fieldId.FieldName == "Name"
- Eşleşme başarısız oluyor:
fieldId.FieldName == "name"
- Eşleşme başarısız oluyor:
fieldId.FieldName == "NAME"
- Eşleşme başarısız oluyor:
fieldId.FieldName == "nAmE"
öğesine Model
ek bir özellik ekleyin, örneğin:
[StringLength(10, ErrorMessage = "Description is too long.")]
public string? Description { get; set; }
Description
öğesini bileşenin formuna CustomValidationForm
ekleyin:
<InputText @bind-Value="Model!.Description" />
Bileşenin EditContext OnInitialized
yöntemindeki örneği yeni Alan CSS Sınıf Sağlayıcısını kullanacak şekilde güncelleştirin:
editContext?.SetFieldCssClassProvider(new CustomFieldClassProvider2());
CsS doğrulama sınıfı alana uygulanmadığından Description
stil uygulanmaz. Ancak, alan doğrulaması normal şekilde çalışır. 10'dan fazla karakter sağlanırsa doğrulama özeti şu hatayı gösterir:
Açıklama çok uzun.
Aşağıdaki örnekte:
Alana özel CSS stili uygulanır
Name
.Diğer tüm alanlar, 'nin varsayılan mantığına Blazorbenzer bir mantık uygular ve veya
invalid
ile 'valid
nin varsayılan alan CSS doğrulama stillerinimodified
kullanırBlazor. Varsayılan stiller için, uygulama bir Blazor proje şablonunu temel alırsa bunları uygulamanın stil sayfasına eklemeniz gerekmediğini unutmayın. Proje şablonuna Blazor dayalı olmayan uygulamalar için, varsayılan stiller uygulamanın stil sayfasına eklenebilir:.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";
}
}
}
}
Bileşenin EditContext OnInitialized
yöntemindeki örneği önceki Alan CSS Sınıf Sağlayıcısını kullanacak şekilde güncelleştirin:
editContext.SetFieldCssClassProvider(new CustomFieldClassProvider3());
kullanarak CustomFieldClassProvider3
:
- alanı,
Name
uygulamanın özel doğrulama CSS stillerini kullanır. - alanı,
Description
'nin mantığına Blazorve Blazor'nin varsayılan alanı CSS doğrulama stillerine benzer bir mantık kullanır.
ile sınıf düzeyi doğrulama IValidatableObject
Form modelleri için (API belgeleri) ile IValidatableObject
sınıf düzeyinde doğrulama desteklenir.Blazor IValidatableObject doğrulama yalnızca form gönderildiğinde ve yalnızca diğer tüm doğrulamalar başarılı olursa yürütülür.
Blazor veri ek açıklamaları doğrulama paketi
Microsoft.AspNetCore.Components.DataAnnotations.Validation
, bileşeni kullanarak DataAnnotationsValidator doğrulama deneyimi boşluklarını dolduran bir pakettir. Paket şu anda deneyseldir.
Uyarı
Paket, Microsoft.AspNetCore.Components.DataAnnotations.Validation
NuGet.org sürüm adayının en son sürümüne sahiptir. Şu anda deneysel sürüm adayı paketini kullanmaya devam edin. Deneysel özellikler, özelliğin uygulanabilirliğini incelemek amacıyla kullanılır ve kararlı bir sürümde gönderilmeyebilir. Daha fazla güncelleştirme için Duyurular GitHub deposunudotnet/aspnetcore
, GitHub deposunu veya bu konu başlığını izleyin.
[CompareProperty]
özniteliği
CompareAttribute, doğrulama sonucunu belirli bir üyeyle ilişkilendirmediğinden bileşeniyle DataAnnotationsValidator DataAnnotationsValidator iyi çalışmaz. Bu, alan düzeyi doğrulama ile bir gönderme sırasında modelin tamamı doğrulandığında arasında tutarsız davranışa neden olabilir. Deneysel Microsoft.AspNetCore.Components.DataAnnotations.Validation
paket, ComparePropertyAttribute
bu sınırlamaları geçici olarak karşılayan ek bir doğrulama özniteliği ekler. Bir uygulamada, [CompareProperty]
özniteliğinin doğrudan yerini alır[Compare]
.Blazor
İç içe modeller, koleksiyon türleri ve karmaşık türler
Blazor yerleşik DataAnnotationsValidatorile veri ek açıklamalarını kullanarak form girişini doğrulama desteği sağlar. Ancak, DataAnnotationsValidator yalnızca koleksiyon veya karmaşık tür özellikleri olmayan forma bağlı modelin üst düzey özelliklerini doğrular.
İlişkili modelin koleksiyon ve karmaşık tür özellikleri de dahil olmak üzere nesne grafiğinin tamamını doğrulamak için deneysel Microsoft.AspNetCore.Components.DataAnnotations.Validation
paket tarafından sağlanan öğesini ObjectGraphDataAnnotationsValidator
kullanın:
<EditForm ...>
<ObjectGraphDataAnnotationsValidator />
...
</EditForm>
ile [ValidateComplexType]
model özelliklerine açıklama ekleyin. Aşağıdaki model sınıflarında sınıfı, modelin ShipDescription
forma bağlı olduğunu doğrulamak için ek veri ek açıklamaları içerir:
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; }
}
Form doğrulamaya göre gönder düğmesini etkinleştirme
Form doğrulamaya göre gönder düğmesini etkinleştirmek ve devre dışı bırakmak için aşağıdaki örnek:
- Giriş bileşenleri makalesinin Örnek form bölümünün önceki
Starfleet Starship Database
formunun (Starship3
bileşen) kısaltılmış bir sürümünü kullanır ve bu sürüm yalnızca geminin kimliği için bir değer kabul eder. Türün bir örneğiStarship
oluşturulduğunda diğerStarship
özellikler geçerli varsayılan değerler alır. - Bileşen başlatıldığında modeli atamak için formun EditContext formlarını kullanır.
- Gönder düğmesini etkinleştirmek ve devre dışı bırakmak için bağlamın OnFieldChanged geri çağırmasında formu doğrular.
- IDisposable yönteminde
Dispose
olay işleyicisini uygular ve aboneliğini iptal eder. Daha fazla bilgi için bkz. ASP.NET Core Razor bileşeni yaşam döngüsü.
Not
öğesine EditForm.EditContextatarken, öğesine de atamayın EditForm.Model EditForm.
Starship14.razor
:
@page "/starship-14"
@implements IDisposable
@inject ILogger<Starship14> Logger
<EditForm EditContext="editContext" OnValidSubmit="Submit" FormName="Starship14">
<DataAnnotationsValidator />
<ValidationSummary />
<div>
<label>
Identifier:
<InputText @bind-Value="Model!.Id" />
</label>
</div>
<div>
<button type="submit" disabled="@formInvalid">Submit</button>
</div>
</EditForm>
@code {
private bool formInvalid = false;
private EditContext? editContext;
[SupplyParameterFromForm]
private Starship? Model { get; set; }
protected override void OnInitialized()
{
Model ??=
new()
{
Id = "NCC-1701",
Classification = "Exploration",
MaximumAccommodation = 150,
IsValidatedDesign = true,
ProductionDate = new DateTime(2245, 4, 11)
};
editContext = new(Model);
editContext.OnFieldChanged += HandleFieldChanged;
}
private void HandleFieldChanged(object? sender, FieldChangedEventArgs e)
{
if (editContext is not null)
{
formInvalid = !editContext.Validate();
StateHasChanged();
}
}
private void Submit() => Logger.LogInformation("Submit: Processing form");
public void Dispose()
{
if (editContext is not null)
{
editContext.OnFieldChanged -= HandleFieldChanged;
}
}
}
@page "/starship-14"
@implements IDisposable
@inject ILogger<Starship14> Logger
<EditForm EditContext="editContext" OnValidSubmit="Submit" FormName="Starship14">
<DataAnnotationsValidator />
<ValidationSummary />
<div>
<label>
Identifier:
<InputText @bind-Value="Model!.Id" />
</label>
</div>
<div>
<button type="submit" disabled="@formInvalid">Submit</button>
</div>
</EditForm>
@code {
private bool formInvalid = false;
private EditContext? editContext;
[SupplyParameterFromForm]
private Starship? Model { get; set; }
protected override void OnInitialized()
{
Model ??=
new()
{
Id = "NCC-1701",
Classification = "Exploration",
MaximumAccommodation = 150,
IsValidatedDesign = true,
ProductionDate = new DateTime(2245, 4, 11)
};
editContext = new(Model);
editContext.OnFieldChanged += HandleFieldChanged;
}
private void HandleFieldChanged(object? sender, FieldChangedEventArgs e)
{
if (editContext is not null)
{
formInvalid = !editContext.Validate();
StateHasChanged();
}
}
private void Submit() => Logger.LogInformation("Submit: Processing form");
public void Dispose()
{
if (editContext is not null)
{
editContext.OnFieldChanged -= HandleFieldChanged;
}
}
}
@page "/starship-14"
@implements IDisposable
@inject ILogger<Starship14> Logger
<EditForm EditContext="editContext" OnValidSubmit="Submit">
<DataAnnotationsValidator />
<ValidationSummary />
<div>
<label>
Identifier:
<InputText @bind-Value="Model!.Id" />
</label>
</div>
<div>
<button type="submit" disabled="@formInvalid">Submit</button>
</div>
</EditForm>
@code {
private bool formInvalid = false;
private EditContext? editContext;
private Starship? Model { get; set; }
protected override void OnInitialized()
{
Model ??=
new()
{
Id = "NCC-1701",
Classification = "Exploration",
MaximumAccommodation = 150,
IsValidatedDesign = true,
ProductionDate = new DateTime(2245, 4, 11)
};
editContext = new(Model);
editContext.OnFieldChanged += HandleFieldChanged;
}
private void HandleFieldChanged(object? sender, FieldChangedEventArgs e)
{
if (editContext is not null)
{
formInvalid = !editContext.Validate();
StateHasChanged();
}
}
private void Submit()
{
Logger.LogInformation("Submit called: Processing the form");
}
public void Dispose()
{
if (editContext is not null)
{
editContext.OnFieldChanged -= HandleFieldChanged;
}
}
}
Form geçerli değerlerle önceden yüklenmemişse ve form yüklemesinde düğmeyi Submit
devre dışı bırakmak istiyorsanız olarak ayarlayın formInvalid
true
.
Önceki yaklaşımın bir yan etkisi, kullanıcı herhangi bir alanla etkileşime geçtikten sonra bir doğrulama özetinin (ValidationSummary bileşen) geçersiz alanlarla doldurulmadır. Bu senaryoyu aşağıdaki yollardan biriyle ele alın:
- Formda bileşen ValidationSummary kullanmayın.
- ValidationSummary Gönder düğmesi seçildiğinde bileşeni görünür hale getirin (örneğin, bir
Submit
yöntemde).
<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";
}
}
ASP.NET Core