Aracılığıyla paylaş


ASP.NET Core Blazor form doğrulaması

Not

Bu, bu makalenin en son sürümü değildir. Geçerli sürüm için bu makalenin .NET 8 sürümüne bakın.

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.

Önemli

Bu bilgiler, ticari olarak piyasaya sürülmeden önce önemli ölçüde değiştirilebilen bir yayın öncesi ürünle ilgilidir. Burada verilen bilgilerle ilgili olarak Microsoft açık veya zımni hiçbir garanti vermez.

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, CustomValidationbu 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çindeki Dictionary<string, List<string>>yöntemine DisplayErrors 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ı BlazorSamplebelirtir.

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 (Starship3bileş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:

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.

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.Accessfarklıysa ek özelleştirme gerekir.

Güvenlik hakkında daha fazla bilgi için bkz:

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:

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 onchangechangeolayı (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 SaladChefValidatorAttributeSaladIngredient([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 Namestring.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 Modelek 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 invalidile 'validnin varsayılan alan CSS doğrulama stillerini modified 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, ComparePropertyAttributebu 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 (Starship3bileş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ği Starship oluşturulduğunda diğer Starship ö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:

<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";
    }
}