Megosztás a következőn keresztül:


ASP.NET Core Blazor űrlapok érvényesítése

Jegyzet

Ez nem a cikk legújabb verziója. Az aktuális kiadásról a cikk .NET 10-es verziójában olvashat.

Figyelmeztetés

A ASP.NET Core ezen verziója már nem támogatott. További információ: .NET és .NET Core támogatási szabályzat. Az aktuális kiadásért tekintse meg ennek a cikknek a .NET 9-es verzióját.

Ez a cikk bemutatja, hogyan használható az ellenőrzés Blazor űrlapokon.

Űrlap érvényesítése

Az alapszintű űrlapérvényesítési forgatókönyvekben egy EditForm-példány deklarált EditContext és ValidationMessageStore példányokkal érvényesítheti az űrlapmezőket. A OnValidationRequestedEditContext eseményének kezelője egyedi érvényesítési logikát hajt végre. A kezelő eredménye frissíti a ValidationMessageStore-példányt.

Az egyszerű űrlapérvényesítés akkor hasznos, ha az űrlap modelljét az űrlapot üzemeltető összetevőben definiálják, akár közvetlenül az összetevő tagjaiként, akár egy alosztályban. Az érvényesítő összetevő használata javasolt, ahol több összetevőhöz is használnak független modellosztályt.

Az Blazor Web App-ek esetében az ügyféloldali ellenőrzéshez aktív BlazorSignalR kapcsolatcsoport szükséges. Az ügyféloldali ellenőrzés nem érhető el a statikus kiszolgálóoldali renderelést (statikus SSR) használó összetevők űrlapjai számára. A statikus SSR-t alkalmazó űrlapok az űrlap elküldése után érvényesítve lesznek a kiszolgálón.

Az alábbi összetevőben a HandleValidationRequested kezelő metódus törli a meglévő érvényesítési üzeneteket úgy, hogy meghívja ValidationMessageStore.Clear az űrlap ellenőrzése előtt.

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

Data Annotations Validator komponens és testreszabott ellenőrzés

A DataAnnotationsValidator összetevő az adatjegyzetek érvényesítését egy kaszkádolt EditContext-hez csatolja. Az adatjegyzetek érvényesítésének engedélyezéséhez a DataAnnotationsValidator összetevőre van szükség. Ha más érvényesítési rendszert szeretne használni, mint az adatjegyzeteket, a DataAnnotationsValidator összetevő helyett használjon egyéni implementációt. A referenciaforrásban a DataAnnotationsValidator keretrendszer-implementációi megtekinthetők:

Az érvényesítési viselkedéssel kapcsolatos részletekért tekintse meg az érvényesítési viselkedés szakasztDataAnnotationsValidator.

Ha engedélyeznie kell az adatjegyzetek érvényesítési támogatását EditContext-hoz, hívja meg a EnableDataAnnotationsValidation egy injektált IServiceProvider (@inject IServiceProvider ServiceProvider)-val a EditContext-on. Egy speciális példát a ASP.NET Core NotifyPropertyChangedValidationComponent-keretrendszer Blazor (BasicTestApp GitHub-adattár) dotnet/aspnetcore összetevőjében talál. A példa éles verziójában a szolgáltató new TestServiceProvider() argumentumát cserélje le egy beillesztett IServiceProvider-re.

Jegyzet

A .NET referenciaforrásra mutató dokumentációs hivatkozások általában betöltik az adattár alapértelmezett ágát, amely a .NET következő kiadásának aktuális fejlesztését jelöli. Egy adott kiadás címkéjének kiválasztásához használja az Ágak és címkék legördülő listát. További információ: A ASP.NET Core-forráskód (dotnet/AspNetCore.Docs #26205) verziócímkéjének kiválasztása.

Blazor kétféle ellenőrzést hajt végre:

  • A mező érvényesítése akkor történik, amikor a felhasználó kilép egy mezőből. A mezőérvényesítés során a DataAnnotationsValidator összetevő az összes jelentett érvényesítési eredményt társítja a mezőhöz.
  • A modell ellenőrzése akkor történik meg, amikor a felhasználó elküldi az űrlapot. A modell érvényesítése során a DataAnnotationsValidator összetevő megkísérli meghatározni a mezőt annak a tagnak a neve alapján, amelyet az érvényesítési eredmény jelent. Az egyes tagokkal nem társított érvényesítési eredmények mező helyett a modellhez vannak társítva.

Egyéni érvényesítési forgatókönyvekben:

Az egyéni ellenőrzés megvalósításának két általános megközelítése van, amelyeket a cikk következő két szakaszában ismertetünk:

  • Manuális érvényesítés az OnValidationRequested esemény: Az űrlap mezőinek manuális ellenőrzése adatjegyeken keresztül és egyéni mezőellenőrzési kód alkalmazásával, amikor az ellenőrzést az OnValidationRequested eseményhez rendelt eseménykezelőn keresztül kérik.
  • Validator-összetevők: Egy vagy több egyéni érvényesítő összetevő használható az ugyanazon az oldalon vagy ugyanazon űrlapon található különböző űrlapok érvényesítésének feldolgozásához az űrlapfeldolgozás különböző lépéseinél (például ügyfélérvényesítés, majd kiszolgálóérvényesítés).

Manuális érvényesítés a OnValidationRequested esemény használatával

A EditContext.OnValidationRequested eseményhez rendelt egyéni eseménykezelővel manuálisan ellenőrizheti az űrlapokat a ValidationMessageStorekezeléséhez.

A Blazor keretrendszer biztosítja a DataAnnotationsValidator összetevőt, amely további érvényesítési támogatást biztosít az űrlapokhoz érvényesítési attribútumok (adatjegyzetek)alapján.

A korábbi Starship8 összetevő példáját felidézve a HandleValidationRequested metódus hozzá van rendelve OnValidationRequested, ahol manuális ellenőrzést végezhet C#-kódban. Néhány módosítás azt mutatja be, hogy a meglévő manuális ellenőrzés és az adatjegyzetek érvényesítése egy DataAnnotationsValidator és a Holodeck modellre alkalmazott érvényesítési attribútum segítségével kombinálható.

Hivatkozzon a System.ComponentModel.DataAnnotations névtérre az összetevő definíciós fájljának tetején található Razor irányelvekben.

@using System.ComponentModel.DataAnnotations

Adjon hozzá egy Id tulajdonságot a Holodeck modellhez egy érvényesítési attribútummal, amely a sztring hosszát hat karakterre korlátozza:

[StringLength(6)]
public string? Id { get; set; }

Adjon hozzá egy DataAnnotationsValidator összetevőt (<DataAnnotationsValidator />) az űrlaphoz. Az összetevő általában közvetlenül a <EditForm> címke alá kerül, de az űrlapon bárhol elhelyezheti:

<DataAnnotationsValidator />

Módosítsa az űrlap küldési viselkedését a <EditForm> címkében OnSubmit-ról OnValidSubmit-ra, amely biztosítja, hogy az űrlap érvényes legyen a hozzárendelt eseménykezelő metódus végrehajtása előtt:

- OnSubmit="Submit"
+ OnValidSubmit="Submit"

A <EditForm>-nál adjon hozzá egy mezőt a Id tulajdonsághoz:

<div>
    <label>
        <InputText @bind-Value="Model!.Id" />
        ID (6 characters max)
    </label>
    <ValidationMessage For="() => Model!.Id" />
</div>

Az előző módosítások elvégzése után az űrlap viselkedése megegyezik a következő specifikációval:

  • Az adatjegyzetek érvényesítése a Id tulajdonságon nem vált ki érvényesítési hibát, ha a Id mező csak a fókuszt veszíti el. Az érvényesítés akkor lesz végrehajtva, amikor a felhasználó kiválasztja a Update gombot.
  • Az űrlap HandleValidationRequested eseményéhez rendelt OnValidationRequested metódusban végrehajtandó manuális ellenőrzés akkor lesz végrehajtva, ha a felhasználó kiválasztja az űrlap Update gombját. A Starship8 összetevő példájának meglévő kódjában a felhasználónak ki kell jelölnie vagy mindkét jelölőnégyzetet az űrlap érvényesítéséhez.
  • Az űrlap csak akkor dolgozza fel a Submit metódust, miután mind az adatjegyzetek, mind a manuális érvényesítés sikeresen lezajlott.

Érvényesítő összetevők

Az érvényesítő összetevők az űrlap ValidationMessageStoreEditContext-jának kezelésével támogatják az űrlapok érvényesítését.

A Blazor keretrendszer biztosítja a DataAnnotationsValidator összetevőt, amely érvényesítési támogatást csatol az űrlapokhoz érvényesítési attribútumok (adatjegyzetek)alapján. Létrehozhat egyéni érvényesítő összetevőket, amelyekkel különböző űrlapok érvényesítési üzeneteit dolgozhatja fel ugyanazon az oldalon vagy ugyanazon az űrlapon az űrlapfeldolgozás különböző lépéseinél (például ügyfélérvényesítés, majd kiszolgálóérvényesítés). Az ebben a szakaszban látható validátor-összetevő-példát (CustomValidation) a cikk következő szakaszaiban használjuk:

Az beépített adatjegyzet-érvényesítők közülcsak a [Remote] érvényesítési attribútum nem támogatott a Blazor.

Jegyzet

Az egyéni adatjegyzet-érvényesítési attribútumok sok esetben használhatók egyéni érvényesítő összetevők helyett. Az űrlap modelljére alkalmazott egyéni attribútumok a DataAnnotationsValidator összetevő használatával aktiválódnak. A kiszolgáló érvényesítésekor a modellre alkalmazott egyéni attribútumoknak végrehajthatónak kell lenniük a kiszolgálón. További információért lásd a Egyéni érvényesítési attribútumok szakaszt.

Készítsen egy ComponentBaseérvényesítő komponenst.

  • Az űrlap EditContext az összetevő kaszkádolt paramétere.
  • Az érvényesítő összetevő inicializálásakor egy új ValidationMessageStore jön létre az űrlaphibák aktuális listájának fenntartásához.
  • Az üzenettároló hibaüzeneteket kap, amikor az űrlap összetevőjében található fejlesztői kód meghívja a DisplayErrors metódust. A hibák a DisplayErrors metódushoz lesznek átadva egy Dictionary<string, List<string>>-ben. A szótárban a kulcs annak az űrlapmezőnek a neve, amely egy vagy több hibát jelez. Az érték a hibalista.
  • Az üzenetek törlődnek, ha az alábbiak bármelyike előfordult:
    • Az érvényesítés a EditContext esemény felmerülésekor kérődik a OnValidationRequested-ra. Az összes hiba törlődik.
    • Egy mező megváltozik az űrlapon a OnFieldChanged esemény létrehozásakor. Csak a mező hibái törlődnek.
    • A ClearErrors metódust fejlesztői kód hívja meg. Az összes hiba törlődik.

Frissítse a névteret az alábbi osztályban, hogy megfeleljen az alkalmazás névterének.

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();
    }
}

Fontos

A névtér megadása szükségesComponentBase. Ha nem adja meg a névteret, az buildelési hibát eredményezi:

Tag helpers cannot target tag name '<global namespace>.{CLASS NAME}' because it contains a ' ' character.

A {CLASS NAME} helyőrző az összetevőosztály neve. Az ebben a szakaszban található egyéni érvényesítő példa megadja a példanévteret BlazorSample.

Jegyzet

A névtelen lambda-kifejezések az előző példában szereplő OnValidationRequested és OnFieldChanged regisztrált eseménykezelői. Ebben a forgatókönyvben nem szükséges implementálni IDisposable és leiratkozni az eseménydelegáltakról. További információért lásd: ASP.NET Core Razor összetevők kezelése vagy eltávolítása.

Üzleti logika validálása egy validálási összetevővel

Az általános üzleti logika érvényesítéséhez használjon egy érvényesítő összetevőt, amely űrlaphibákat kap egy szótárban.

Az alapszintű ellenőrzés akkor hasznos, ha az űrlap modelljét az űrlapot üzemeltető összetevőben definiálják, akár közvetlenül az összetevő tagjaiként, akár egy alosztályban. Az érvényesítő összetevő használata akkor ajánlott, ha egy független modellosztályt használnak több összetevőben.

Az alábbi példában:

  • A Starfleet Starship Database űrlap (Starship3 összetevő) rövidített változata használatos a bemeneti komponensek cikkének példaurak szakaszában, amely csak a csillaghajó besorolását és leírását fogadja el. Az adatjegyzet-ellenőrzés nem aktiválódik az űrlap beküldésekor, mert az DataAnnotationsValidator összetevő nem szerepel az űrlapban.
  • A cikk CustomValidation szakaszának összetevőjét használja.
  • Az ellenőrzéshez a hajó leírásának (Description) értékére van szükség, ha a felhasználó a "Defense" hajóbesorolást (Classification) választja.

Ha az érvényesítési üzenetek be vannak állítva az összetevőben, azokat hozzáadják az érvényesítő ValidationMessageStore-hoz, és megjelennek a EditFormérvényesítési összegzésében.

Starship9.razor:

@page "/starship-9"
@inject ILogger<Starship9> Logger

<h1>Starfleet Starship Database</h1>

<h2>New Ship Entry Form</h2>

<EditForm Model="Model" OnValidSubmit="Submit" FormName="Starship9">
    <CustomValidation @ref="customValidation" />
    <ValidationSummary />
    <div>
        <label>
            Primary Classification:
            <InputSelect @bind-Value="Model!.Classification">
                <option value="">
                    Select classification ...
                </option>
                <option checked="@(Model!.Classification == "Exploration")" 
                    value="Exploration">
                    Exploration
                </option>
                <option checked="@(Model!.Classification == "Diplomacy")" 
                    value="Diplomacy">
                    Diplomacy
                </option>
                <option checked="@(Model!.Classification == "Defense")" 
                    value="Defense">
                    Defense
                </option>
            </InputSelect>
        </label>
    </div>
    <div>
        <label>
            Description (optional):
            <InputTextArea @bind-Value="Model!.Description" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    private CustomValidation? customValidation;

    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized() =>
        Model ??= new() { ProductionDate = DateTime.UtcNow };

    private void Submit()
    {
        customValidation?.ClearErrors();

        var errors = new Dictionary<string, List<string>>();

        if (Model!.Classification == "Defense" &&
                string.IsNullOrEmpty(Model.Description))
        {
            errors.Add(nameof(Model.Description),
                [ "For a 'Defense' ship classification, " +
                "'Description' is required." ]);
        }

        if (errors.Any())
        {
            customValidation?.DisplayErrors(errors);
        }
        else
        {
            Logger.LogInformation("Submit called: Processing the form");
        }
    }
}
@page "/starship-9"
@inject ILogger<Starship9> Logger

<h1>Starfleet Starship Database</h1>

<h2>New Ship Entry Form</h2>

<EditForm Model="Model" OnValidSubmit="Submit" FormName="Starship9">
    <CustomValidation @ref="customValidation" />
    <ValidationSummary />
    <div>
        <label>
            Primary Classification:
            <InputSelect @bind-Value="Model!.Classification">
                <option value="">
                    Select classification ...
                </option>
                <option checked="@(Model!.Classification == "Exploration")" 
                    value="Exploration">
                    Exploration
                </option>
                <option checked="@(Model!.Classification == "Diplomacy")" 
                    value="Diplomacy">
                    Diplomacy
                </option>
                <option checked="@(Model!.Classification == "Defense")" 
                    value="Defense">
                    Defense
                </option>
            </InputSelect>
        </label>
    </div>
    <div>
        <label>
            Description (optional):
            <InputTextArea @bind-Value="Model!.Description" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    private CustomValidation? customValidation;

    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized() =>
        Model ??= new() { ProductionDate = DateTime.UtcNow };

    private void Submit()
    {
        customValidation?.ClearErrors();

        var errors = new Dictionary<string, List<string>>();

        if (Model!.Classification == "Defense" &&
                string.IsNullOrEmpty(Model.Description))
        {
            errors.Add(nameof(Model.Description),
                [ "For a 'Defense' ship classification, " +
                "'Description' is required." ]);
        }

        if (errors.Any())
        {
            customValidation?.DisplayErrors(errors);
        }
        else
        {
            Logger.LogInformation("Submit called: Processing the form");
        }
    }
}
@page "/starship-9"
@inject ILogger<Starship9> Logger

<h1>Starfleet Starship Database</h1>

<h2>New Ship Entry Form</h2>

<EditForm Model="Model" OnValidSubmit="Submit">
    <CustomValidation @ref="customValidation" />
    <ValidationSummary />
    <div>
        <label>
            Primary Classification:
            <InputSelect @bind-Value="Model!.Classification">
                <option value="">Select classification ...</option>
                <option value="Exploration">Exploration</option>
                <option value="Diplomacy">Diplomacy</option>
                <option value="Defense">Defense</option>
            </InputSelect>
        </label>
    </div>
    <div>
        <label>
            Description (optional):
            <InputTextArea @bind-Value="Model!.Description" />
        </label>
    </div>
    <div>
        <button type="submit">Submit</button>
    </div>
</EditForm>

@code {
    private CustomValidation? customValidation;

    public Starship? Model { get; set; }

    protected override void OnInitialized() =>
        Model ??= new() { ProductionDate = DateTime.UtcNow };

    private void Submit()
    {
        customValidation?.ClearErrors();

        var errors = new Dictionary<string, List<string>>();

        if (Model!.Classification == "Defense" &&
                string.IsNullOrEmpty(Model.Description))
        {
            errors.Add(nameof(Model.Description),
                new() { "For a 'Defense' ship classification, " +
                "'Description' is required." });
        }

        if (errors.Any())
        {
            customValidation?.DisplayErrors(errors);
        }
        else
        {
            Logger.LogInformation("Submit called: Processing the form");
        }
    }
}

Jegyzet

Az érvényesítési összetevőkhasználata helyett az adatjegyzet-érvényesítési attribútumok használhatók. Az űrlap modelljére alkalmazott egyéni attribútumok a DataAnnotationsValidator összetevő használatával aktiválódnak. A kiszolgáló érvényesítésekor az attribútumoknak végrehajthatónak kell lenniük a kiszolgálón. További információért lásd a Egyéni érvényesítési attribútumok szakaszt.

Kiszolgáló érvényesítése egy érvényesítő komponenssel

Ez a szakasz Blazor Web App forgatókönyvekre összpontosít, de a web API-val kiszolgálóérvényesítést használó alkalmazások megközelítése ugyanazt az általános megközelítést alkalmazza.

Ez a szakasz az üzemeltetett Blazor WebAssembly forgatókönyvekre összpontosít, de a web API-val kiszolgálóérvényesítést használó alkalmazások megközelítése ugyanazt az általános megközelítést alkalmazza.

A kiszolgáló érvényesítése az ügyfélérvényesítés mellett támogatott:

  • Dolgozza fel az ügyfélérvényesítést az űrlapon a DataAnnotationsValidator komponenssel.
  • Amikor az űrlap átadja az ügyfélérvényesítést (OnValidSubmit van hívva), küldje el a EditContext.Model-et egy háttérkiszolgáló API-jának űrlapfeldolgozás céljából.
  • Folyamatmodell érvényesítése a kiszolgálón.
  • A kiszolgálói API tartalmazza a beépített keretrendszer adatjegyzetek érvényesítését és a fejlesztő által biztosított egyéni érvényesítési logikát is. Ha az ellenőrzés sikeres a kiszolgálón, dolgozza fel az űrlapot, és küldjön vissza egy sikeres állapotkódot (200 - OK). Ha az ellenőrzés sikertelen, adja vissza a hibaállapot-kódot (400 - Bad Request) és a mezőérvényesítési hibákat.
  • Siker esetén tiltsa le az űrlapot, vagy jelenítse meg a hibákat.

Az alapszintű ellenőrzés akkor hasznos, ha az űrlap modelljét az űrlapot üzemeltető összetevőben definiálják, akár közvetlenül az összetevő tagjaiként, akár egy alosztályban. Az érvényesítő összetevő használata akkor ajánlott, ha egy független modellosztályt használnak több összetevőben.

A következő példa a következőkön alapul:

  • A Blazor Web Applétrehozott Interaktív WebAssembly-összetevőket tartalmazó Blazor Web App.
  • A Starship cikk Starship.cs jának modellje ().
  • A CustomValidation összetevő bemutatva a Validator összetevők szakaszában.

Helyezze a Starship modellt (Starship.cs) egy megosztott osztálytárprojektbe, hogy az ügyfél- és kiszolgálóprojektek is használhassák a modellt. Adja hozzá vagy frissítse a névteret a megosztott alkalmazás névterének megfelelően (például namespace BlazorSample.Shared). Mivel a modell adatjegyzeteket igényel, győződjön meg arról, hogy a megosztott osztálykódtár a megosztott keretrendszert használja, vagy adja hozzá a System.ComponentModel.Annotations csomagot a megosztott projekthez.

Jegyzet

A csomagok .NET-alkalmazásokhoz való hozzáadásáról a Csomagok telepítése és kezeléseCsomaghasználati munkafolyamat (NuGet-dokumentáció)című cikkben talál útmutatást. Ellenőrizze a megfelelő csomagverziókat a NuGet.org.

A Blazor Web Appfő projektjében adjon hozzá egy vezérlőt a csillaghajó-ellenőrzési kérések feldolgozásához, és küldje vissza a sikertelen érvényesítési üzeneteket. Frissítse a névtereket a megosztott osztálykönyvtár projekt utolsó using utasításában, valamint a vezérlőosztály namespace utasításában. Az ügyfél- és kiszolgálóadat-megjegyzések ellenőrzése mellett a vezérlő ellenőrzi, hogy a hajó leírásához (Description) érték van-e megadva, ha a felhasználó kiválasztja a Defense hajóosztályozást (Classification).

  • A Blazor WebAssembly projektsablonbóllétrehozott üzemeltetett Blazor WebAssemblymegoldás. A megközelítés támogatott bármelyik, a biztonsági dokumentáció Blazoráltal ismertetett biztonságos üzemeltetésű Blazor WebAssembly megoldások esetében.
  • A Starship cikk Starship.cs jának modellje ().
  • A CustomValidation összetevő bemutatva a Validator összetevők szakaszában.

Helyezze a Starship modellt (Starship.cs) a megoldás Shared projektbe, hogy az ügyfél- és kiszolgálóalkalmazások is használhassák a modellt. Adja hozzá vagy frissítse a névteret a megosztott alkalmazás névterének megfelelően (például namespace BlazorSample.Shared). Mivel a modell adatjegyzeteket igényel, adja hozzá a System.ComponentModel.Annotations csomagot a Shared projekthez.

Jegyzet

A csomagok .NET-alkalmazásokhoz való hozzáadásáról a Csomagok telepítése és kezeléseCsomaghasználati munkafolyamat (NuGet-dokumentáció)című cikkben talál útmutatást. Ellenőrizze a megfelelő csomagverziókat a NuGet.org.

A Server projektben adjon hozzá egy vezérlőt a csillaghajó-ellenőrzési kérések feldolgozásához, és adjon vissza sikertelen ellenőrzési üzeneteket. Frissítse a névtereket a using projekt utolsó Shared utasításában és a namespace-t a vezérlőosztályban. Az ügyfél- és kiszolgálóadat-megjegyzések ellenőrzése mellett a vezérlő ellenőrzi, hogy a hajó leírásához (Description) érték van-e megadva, ha a felhasználó kiválasztja a Defense hajóosztályozást (Classification).

A Defense hajóbesorolás érvényesítése csak a szerveren történik a vezérlőben, mert a közelgő űrlap nem hajt végre kliensoldali érvényesítést, amikor az űrlapot elküldik a szerverre. Az ügyfél-ellenőrzés nélküli kiszolgálóérvényesítés gyakori azokban az alkalmazásokban, amelyek a kiszolgálón lévő felhasználói bemenet privát üzleti logikájának érvényesítését igénylik. Előfordulhat például, hogy a felhasználó számára tárolt adatokból származó személyes adatokra szükség lehet a felhasználói adatok ellenőrzéséhez. A privát adatok nyilvánvalóan nem küldhetők el az ügyfélnek ügyfélérvényesítés céljából.

Jegyzet

A jelen szakaszban szereplő StarshipValidation vezérlő a Microsoft Identity 2.0-t használja. A Web API csak azoknak a felhasználóknak fogad el jogkivonatokat, akiknek ehhez az API-hoz "API.Access" hatóköre van. További testreszabásra van szükség, ha az API hatókörének neve eltér API.Access-től.

A biztonsággal kapcsolatos további információkért lásd:

Controllers/StarshipValidation.cs:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using BlazorSample.Shared;

namespace BlazorSample.Server.Controllers;

[Authorize]
[ApiController]
[Route("[controller]")]
public class StarshipValidationController(
    ILogger<StarshipValidationController> logger) 
    : ControllerBase
{
    static readonly string[] scopeRequiredByApi = [ "API.Access" ];

    [HttpPost]
    public async Task<IActionResult> Post(Starship model)
    {
        HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);

        try
        {
            if (model.Classification == "Defense" && 
                string.IsNullOrEmpty(model.Description))
            {
                ModelState.AddModelError(nameof(model.Description),
                    "For a 'Defense' ship " +
                    "classification, 'Description' is required.");
            }
            else
            {
                logger.LogInformation("Processing the form asynchronously");

                // async ...

                return Ok(ModelState);
            }
        }
        catch (Exception ex)
        {
            logger.LogError("Validation Error: {Message}", ex.Message);
        }

        return BadRequest(ModelState);
    }
}
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using BlazorSample.Shared;

namespace BlazorSample.Server.Controllers;

[Authorize]
[ApiController]
[Route("[controller]")]
public class StarshipValidationController(
    ILogger<StarshipValidationController> logger) 
    : ControllerBase
{
    static readonly string[] scopeRequiredByApi = new[] { "API.Access" };

    [HttpPost]
    public async Task<IActionResult> Post(Starship model)
    {
        HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);

        try
        {
            if (model.Classification == "Defense" && 
                string.IsNullOrEmpty(model.Description))
            {
                ModelState.AddModelError(nameof(model.Description),
                    "For a 'Defense' ship " +
                    "classification, 'Description' is required.");
            }
            else
            {
                logger.LogInformation("Processing the form asynchronously");

                // async ...

                return Ok(ModelState);
            }
        }
        catch (Exception ex)
        {
            logger.LogError("Validation Error: {Message}", ex.Message);
        }

        return BadRequest(ModelState);
    }
}

Erősítse meg vagy frissítse az előző vezérlő (BlazorSample.Server.Controllers) névterét az alkalmazás vezérlői névterének megfelelően.

Ha a kiszolgálón modellkötés-érvényesítési hiba történik, a ApiController (ApiControllerAttribute) általában egy alapértelmezett hibás kérésválaszt ad vissza, egy ValidationProblemDetails. A válasz több adatot tartalmaz, mint az érvényesítési hibák, ahogy az alábbi példában is látható, amikor a Starfleet Starship Database űrlap összes mezője nincs elküldve, és az űrlap érvényesítése sikertelen:

{
  "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)." ]
  }
}

Jegyzet

Az előző JSON-válasz bemutatásához le kell tiltania az űrlap ügyfélérvényesítését az üres mezőű űrlap elküldéséhez, vagy egy eszköz használatával közvetlenül a kiszolgáló API-nak kell küldenie a kérést, például Firefox Browser Developer.

Ha a kiszolgálói API az előző alapértelmezett JSON-választ adja vissza, az ügyfél elemezheti a választ a fejlesztői kódban, hogy lekérje a errors csomópont gyermekeit az űrlapérvényesítési hiba feldolgozásához. Nem célszerű fejlesztői kódot írni a fájl elemzéséhez. A JSON manuális elemzéséhez hiba Dictionary<string, List<string>> kell létrehoznia a ReadFromJsonAsynchívása után. Ideális esetben a kiszolgálói API-nak csak az érvényesítési hibákat kell visszaadnia, ahogy az alábbi példa is mutatja:

{
  "Id": [ "The Id field is required." ],
  "Classification": [ "The Classification field is required." ],
  "IsValidatedDesign": [ "This form disallows unapproved ships." ],
  "MaximumAccommodation": [ "Accommodation invalid (1-100000)." ]
}

Ha módosítani szeretné a kiszolgáló API válaszát, hogy csak az érvényesítési hibákat adja vissza, módosítsa a ApiControllerAttribute fájlban Program jegyzetekkel ellátott műveletekre meghívott delegáltat. Az API-végpont (/StarshipValidation) adjon vissza egy BadRequestObjectResult-et a ModelStateDictionary-vel. Bármely más API-végpont esetében őrizze meg az alapértelmezett viselkedést úgy, hogy visszaadja az objektum eredményét egy új ValidationProblemDetails-val.

Adja hozzá a Microsoft.AspNetCore.Mvc névteret a Program fájl elejéhez a Blazor Web Appfő projektjében:

using Microsoft.AspNetCore.Mvc;

A Program fájlban adja hozzá vagy frissítse a következő AddControllersWithViews bővítménymetódust, majd adja hozzá a következő hívást a ConfigureApiBehaviorOptions-hez:

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

Ha először ad hozzá vezérlőket a Blazor Web App fő projektjéhez, akkor a vezérlővégpontok leképezését végezze el, amikor elhelyezi a vezérlőknek szolgáltatásokat regisztráló előző kódot. Az alábbi példa alapértelmezett vezérlőútvonalakat használ:

app.MapDefaultControllerRoute();

Jegyzet

Az előző példa kifejezetten regisztrálja a vezérlőszolgáltatásokat azáltal, hogy meghívja AddControllersWithViews, hogy automatikusan mérsékelje a keresztoldali kéréshamisítási (XSRF/CSRF) támadásokat. Ha csak a AddControllers-et használja, az antiforgery védelem nem engedélyeződik automatikusan.

A vezérlő útválasztási és érvényesítési hibaválaszaival kapcsolatos további információkért tekintse meg a következő erőforrásokat:

A .Client projektben adja hozzá az CustomValidation szakaszban látható összetevőt. Frissítse a névteret az alkalmazásnak megfelelően (például namespace BlazorSample.Client).

A .Client projektben a Starfleet Starship Database űrlap frissül, hogy a kiszolgáló érvényesítési hibái megjelenjenek a CustomValidation összetevő segítségével. Amikor a szerver API érvényesítési üzeneteket ad vissza, azok hozzáadásra kerülnek a CustomValidation komponens ValidationMessageStore-be. A hibák az űrlap EditContext-ban elérhetőek, és megjelennek az űrlap érvényesítési összegzésében.

Az alábbi összetevőben frissítse a megosztott projekt (@using BlazorSample.Shared) névterét a megosztott projekt névterére. Vegye figyelembe, hogy az űrlaphoz engedélyezés szükséges, ezért a felhasználónak be kell jelentkeznie az alkalmazásba az űrlapra való navigáláshoz.

Adja hozzá a Microsoft.AspNetCore.Mvc névteret a Program fájl tetejére az Server alkalmazásban:

using Microsoft.AspNetCore.Mvc;

A Program fájlban keresse meg a AddControllersWithViews bővítménymetódust, és adja hozzá a következő hívást ConfigureApiBehaviorOptions:

builder.Services.AddControllersWithViews()
    .ConfigureApiBehaviorOptions(options =>
    {
        options.InvalidModelStateResponseFactory = context =>
        {
            if (context.HttpContext.Request.Path == "/StarshipValidation")
            {
                return new BadRequestObjectResult(context.ModelState);
            }
            else
            {
                return new BadRequestObjectResult(
                    new ValidationProblemDetails(context.ModelState));
            }
        };
    });

Jegyzet

Az előző példa kifejezetten regisztrálja a vezérlőszolgáltatásokat azáltal, hogy meghívja AddControllersWithViews, hogy automatikusan mérsékelje a keresztoldali kéréshamisítási (XSRF/CSRF) támadásokat. Ha csak a AddControllers-et használja, az antiforgery védelem nem engedélyeződik automatikusan.

A Client projektben adja hozzá az CustomValidation szakaszban látható összetevőt. Frissítse a névteret az alkalmazásnak megfelelően (például namespace BlazorSample.Client).

A Client projektben a Starfleet Starship Database űrlap frissül, hogy a kiszolgáló érvényesítési hibái megjelenjenek a CustomValidation összetevő segítségével. Amikor a szerver API érvényesítési üzeneteket ad vissza, azok hozzáadásra kerülnek a CustomValidation komponens ValidationMessageStore-be. A hibák az űrlap EditContext-ban elérhetőek, és megjelennek az űrlap érvényesítési összegzésében.

Az alábbi összetevőben frissítse a Shared projekt (@using BlazorSample.Shared) névterét a megosztott projekt névterére. Vegye figyelembe, hogy az űrlaphoz engedélyezés szükséges, ezért a felhasználónak be kell jelentkeznie az alkalmazásba az űrlapra való navigáláshoz.

Starship10.razor:

Jegyzet

A EditForm-ra alapuló űrlapok automatikusan engedélyezik a(z) antiforgery támogatást. A vezérlőnek AddControllersWithViews kell használnia a vezérlőszolgáltatások regisztrálásához, és automatikusan engedélyeznie kell az antiforgery támogatást a webes API-hoz.

@page "/starship-10"
@rendermode InteractiveWebAssembly
@using System.Net
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using BlazorSample.Shared
@attribute [Authorize]
@inject HttpClient Http
@inject ILogger<Starship10> Logger

<h1>Starfleet Starship Database</h1>

<h2>New Ship Entry Form</h2>

<EditForm FormName="Starship10" Model="Model" OnValidSubmit="Submit">
    <DataAnnotationsValidator />
    <CustomValidation @ref="customValidation" />
    <ValidationSummary />
    <div>
        <label>
            Identifier: 
            <InputText @bind-Value="Model!.Id" disabled="@disabled" />
        </label>
    </div>
    <div>
        <label>
            Description (optional):
            <InputTextArea @bind-Value="Model!.Description" 
                disabled="@disabled" />
        </label>
    </div>
    <div>
        <label>
            Primary Classification:
            <InputSelect @bind-Value="Model!.Classification" disabled="@disabled">
                <option value="">Select classification ...</option>
                <option value="Exploration">Exploration</option>
                <option value="Diplomacy">Diplomacy</option>
                <option value="Defense">Defense</option>
            </InputSelect>
        </label>
    </div>
    <div>
        <label>
            Maximum Accommodation:
            <InputNumber @bind-Value="Model!.MaximumAccommodation" 
                disabled="@disabled" />
        </label>
    </div>
    <div>
        <label>
            Engineering Approval:
            <InputCheckbox @bind-Value="Model!.IsValidatedDesign" 
                disabled="@disabled" />
        </label>
    </div>
    <div>
        <label>
            Production Date:
            <InputDate @bind-Value="Model!.ProductionDate" disabled="@disabled" />
        </label>
    </div>
    <div>
        <button type="submit" disabled="@disabled">Submit</button>
    </div>
    <div style="@messageStyles">
        @message
    </div>
</EditForm>

@code {
    private CustomValidation? customValidation;
    private bool disabled;
    private string? message;
    private string messageStyles = "visibility:hidden";

    [SupplyParameterFromForm]
    private Starship? Model { get; set; }

    protected override void OnInitialized() => 
        Model ??= new() { ProductionDate = DateTime.UtcNow };

    private async Task Submit(EditContext editContext)
    {
        customValidation?.ClearErrors();

        try
        {
            using var response = await Http.PostAsJsonAsync<Starship>(
                "StarshipValidation", (Starship)editContext.Model);

            var errors = await response.Content
                .ReadFromJsonAsync<Dictionary<string, List<string>>>() ?? 
                new Dictionary<string, List<string>>();

            if (response.StatusCode == HttpStatusCode.BadRequest && 
                errors.Any())
            {
                customValidation?.DisplayErrors(errors);
            }
            else if (!response.IsSuccessStatusCode)
            {
                throw new HttpRequestException(
                    $"Validation failed. Status Code: {response.StatusCode}");
            }
            else
            {
                disabled = true;
                messageStyles = "color:green";
                message = "The form has been processed.";
            }
        }
        catch (AccessTokenNotAvailableException ex)
        {
            ex.Redirect();
        }
        catch (Exception ex)
        {
            Logger.LogError("Form processing error: {Message}", ex.Message);
            disabled = true;
            messageStyles = "color:red";
            message = "There was an error processing the form.";
        }
    }
}

Egy .ClientBlazor Web App projektjének is regisztrálnia kell egy HttpClient-t a HTTP POST-kérelmekhez a háttértár webes API-vezérlőjében. Erősítse meg vagy adja hozzá a következőket a .Client projekt Program fájlhoz:

builder.Services.AddScoped(sp => 
    new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

Az előző példa az alapcímet builder.HostEnvironment.BaseAddress (IWebAssemblyHostEnvironment.BaseAddress) értékre állítja, amely lekéri az alkalmazás alapcímét, és általában a gazdagép oldal <base> címke href értékéből származik.

@page "/starship-10"
@using System.Net
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using BlazorSample.Shared
@attribute [Authorize]
@inject HttpClient Http
@inject ILogger<Starship10> Logger

<h1>Starfleet Starship Database</h1>

<h2>New Ship Entry Form</h2>

<EditForm Model="Model" OnValidSubmit="Submit">
    <DataAnnotationsValidator />
    <CustomValidation @ref="customValidation" />
    <ValidationSummary />
    <div>
        <label>
            Identifier: 
            <InputText @bind-Value="Model!.Id" disabled="@disabled" />
        </label>
    </div>
    <div>
        <label>
            Description (optional):
            <InputTextArea @bind-Value="Model!.Description" 
                disabled="@disabled" />
        </label>
    </div>
    <div>
        <label>
            Primary Classification:
            <InputSelect @bind-Value="Model!.Classification" disabled="@disabled">
                <option value="">Select classification ...</option>
                <option value="Exploration">Exploration</option>
                <option value="Diplomacy">Diplomacy</option>
                <option value="Defense">Defense</option>
            </InputSelect>
        </label>
    </div>
    <div>
        <label>
            Maximum Accommodation:
            <InputNumber @bind-Value="Model!.MaximumAccommodation" 
                disabled="@disabled" />
        </label>
    </div>
    <div>
        <label>
            Engineering Approval:
            <InputCheckbox @bind-Value="Model!.IsValidatedDesign" 
                disabled="@disabled" />
        </label>
    </div>
    <div>
        <label>
            Production Date:
            <InputDate @bind-Value="Model!.ProductionDate" disabled="@disabled" />
        </label>
    </div>
    <div>
        <button type="submit" disabled="@disabled">Submit</button>
    </div>
    <div style="@messageStyles">
        @message
    </div>
</EditForm>

@code {
    private CustomValidation? customValidation;
    private bool disabled;
    private string? message;
    private string messageStyles = "visibility:hidden";

    public Starship? Model { get; set; }

    protected override void OnInitialized() => 
        Model ??= new() { ProductionDate = DateTime.UtcNow };

    private async Task Submit(EditContext editContext)
    {
        customValidation?.ClearErrors();

        try
        {
            using var response = await Http.PostAsJsonAsync<Starship>(
                "StarshipValidation", (Starship)editContext.Model);

            var errors = await response.Content
                .ReadFromJsonAsync<Dictionary<string, List<string>>>() ?? 
                new Dictionary<string, List<string>>();

            if (response.StatusCode == HttpStatusCode.BadRequest && 
                errors.Any())
            {
                customValidation?.DisplayErrors(errors);
            }
            else if (!response.IsSuccessStatusCode)
            {
                throw new HttpRequestException(
                    $"Validation failed. Status Code: {response.StatusCode}");
            }
            else
            {
                disabled = true;
                messageStyles = "color:green";
                message = "The form has been processed.";
            }
        }
        catch (AccessTokenNotAvailableException ex)
        {
            ex.Redirect();
        }
        catch (Exception ex)
        {
            Logger.LogError("Form processing error: {Message}", ex.Message);
            disabled = true;
            messageStyles = "color:red";
            message = "There was an error processing the form.";
        }
    }
}

Jegyzet

A érvényesítési összetevőhasználata helyett adatjegyzet-érvényesítési attribútumok használhatók. Az űrlap modelljére alkalmazott egyéni attribútumok a DataAnnotationsValidator összetevő használatával aktiválódnak. A kiszolgáló érvényesítésekor az attribútumoknak végrehajthatónak kell lenniük a kiszolgálón. További információért lásd a Egyéni érvényesítési attribútumok szakaszt.

Jegyzet

Az ebben a szakaszban szereplő kiszolgálóérvényesítési módszer alkalmas a dokumentációs készletben található üzemeltetett Blazor WebAssembly megoldási példák bármelyikére:

InputText a bemeneti esemény alapján

A InputText összetevővel olyan egyéni összetevőt hozhat létre, amely a oninput esemény (input) helyett a onchange eseményt (change) használja. input esemény használata billentyűleütésenként aktiválja a mezőérvényesítést.

Az alábbi CustomInputText összetevő örökli a keretrendszer InputText összetevőjét, és beállítja az eseménykötést a oninput eseményhez (input).

CustomInputText.razor:

@inherits InputText

<input @attributes="AdditionalAttributes" 
       class="@CssClass" 
       @bind="CurrentValueAsString" 
       @bind:event="oninput" />

A CustomInputText összetevő bárhol alkalmazható, ahol a(z) InputText. A következő összetevő a megosztott CustomInputText összetevőt használja.

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

Érvényesítési összefoglaló és érvényesítési üzenet összetevői

A ValidationSummary összetevő az összes érvényesítési üzenetet összegzi, amely hasonló a Érvényesítési összefoglaló címke segítőhöz:

<ValidationSummary />

Adott modell kimeneti érvényesítési üzenetei a Model paraméterrel:

<ValidationSummary Model="Model" />

A ValidationMessage<TValue> összetevő egy adott mezőre vonatkozó érvényesítési üzeneteket jelenít meg, amely hasonló a érvényesítési üzenetcímkéje súgójának. Adja meg az érvényesítési mezőt a For attribútummal és a modelltulajdonságot elnevező lambda kifejezéssel:

<ValidationMessage For="@(() => Model!.MaximumAccommodation)" />

A ValidationMessage<TValue> és ValidationSummary összetevők tetszőleges attribútumokat támogatnak. A létrehozott <div> vagy <ul> elemhez minden olyan attribútum hozzáadódik, amely nem egyezik meg az összetevőparaméterrel.

Az érvényesítési üzenetek stílusának szabályozása az alkalmazás stíluslapján (wwwroot/css/app.css vagy wwwroot/css/site.css). Az alapértelmezett validation-message osztály pirosra állítja az érvényesítési üzenetek szövegszínét:

.validation-message {
    color: red;
}

Annak megállapítása, hogy egy űrlapmező érvényes-e

A EditContext.IsValid használatával megállapíthatja, hogy egy mező érvényes-e érvényesítési üzenetek beszerzése nélkül.

támogatott, de nem ajánlott:

var isValid = !editContext.GetValidationMessages(fieldIdentifier).Any();

var isValid = editContext.IsValid(fieldIdentifier);

Egyéni érvényesítési attribútumok

Annak érdekében, hogy az érvényesítési eredmény helyesen legyen társítva egy mezőhöz, amikor egyéni érvényesítési attribútumothasznál, adja át az érvényesítési környezet MemberName-t a ValidationResultlétrehozásakor.

CustomValidator.cs:

using System;
using System.ComponentModel.DataAnnotations;

public class CustomValidator : ValidationAttribute
{
    protected override ValidationResult IsValid(object? value, 
        ValidationContext validationContext)
    {
        ...

        return new ValidationResult("Validation message to user.",
            [ validationContext.MemberName! ]);
    }
}
using System;
using System.ComponentModel.DataAnnotations;

public class CustomValidator : ValidationAttribute
{
    protected override ValidationResult IsValid(object? value, 
        ValidationContext validationContext)
    {
        ...

        return new ValidationResult("Validation message to user.",
            new[] { validationContext.MemberName! });
    }
}
using System;
using System.ComponentModel.DataAnnotations;

public class CustomValidator : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, 
        ValidationContext validationContext)
    {
        ...

        return new ValidationResult("Validation message to user.",
            new[] { validationContext.MemberName });
    }
}

Szolgáltatások injektálása egyéni érvényesítési attribútumokba a ValidationContextkeresztül. Az alábbi példa egy salátaséf űrlapot mutat be, amely a felhasználói bemenetet függőséginjektálással (DI) ellenőrzi.

A SaladChef osztály jelzi a Ten Forward saláta jóváhagyott összetevőlistáját a csillaghajón.

SaladChef.cs:

namespace BlazorSample;

public class SaladChef
{
    public string[] SaladToppers = { "Horva", "Kanda Root", "Krintar", "Plomeek",
        "Syto Bean" };
}

Regisztráljon SaladChef az alkalmazás DI-tárolójában a Program fájlban:

builder.Services.AddTransient<SaladChef>();

A következő IsValid osztály SaladChefValidatorAttribute metódusa lekérte a SaladChef szolgáltatást a DI-től a felhasználó bemenetének ellenőrzéséhez.

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

Az alábbi összetevő a SaladChefValidatorAttribute ([SaladChefValidator]) a saláta összetevő sztringjére (SaladIngredient) való alkalmazásával ellenőrzi a felhasználói bemenetet.

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

Egyéni érvényesítési CSS-osztályattribútumok

Az egyéni érvényesítési CSS-osztályattribútumok a CSS-keretrendszerekkel való integráláskor hasznosak, például Bootstrap.

Egyéni érvényesítési CSS-osztályattribútumok megadásához először adjon meg CSS-stílusokat az egyéni ellenőrzéshez. Az alábbi példában érvényes (validField) és érvénytelen (invalidField) stílusok vannak megadva.

Adja hozzá a következő CSS-osztályokat az alkalmazás stíluslapjára:

.validField {
    border-color: lawngreen;
}

.invalidField {
    background-color: tomato;
}

Hozzon létre egy FieldCssClassProvider származó osztályt, amely ellenőrzi a mezőérvényesítési üzeneteket, és alkalmazza a megfelelő érvényes vagy érvénytelen stílust.

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

Állítsa be a CustomFieldClassProvider osztályt az űrlap EditContext példányán mező CSS osztályszolgáltatónak a SetFieldCssClassProviderhasználatával.

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

Az előző példa ellenőrzi az összes űrlapmező érvényességét, és stílust alkalmaz az egyes mezőkre. Ha az űrlapnak csak egyéni stílusokat kell alkalmaznia a mezők egy részhalmazára, tegye CustomFieldClassProvider feltételesen alkalmazni a stílusokat. Az alábbi CustomFieldClassProvider2 példa csak a Name mezőre alkalmaz stílust. A Namenem egyező neveket tartalmazó mezők esetében a string.Empty lesz visszaadva, és nincs stílus alkalmazva. A tükröződésalkalmazásával a mezőt a modell tagjának tulajdonságához vagy mező nevéhez igazítják, nem pedig a HTML entitáshoz rendelt id-hoz/hez.

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

Jegyzet

Az előző példában a mezőnév egyeztetése kis- és nagybetű-érzékeny, ezért a "Name" kijelölt modelltulajdonság tagnak meg kell egyeznie a "Name" feltételes ellenőrzésével.

  • ✔️ helyesen egyezik:fieldId.FieldName == "Name"
  • Nem egyezik:fieldId.FieldName == "name"
  • Nem egyezik:fieldId.FieldName == "NAME"
  • Nem egyezik:fieldId.FieldName == "nAmE"

Adjon hozzá egy további tulajdonságot Model, például:

[StringLength(10, ErrorMessage = "Description is too long.")]
public string? Description { get; set; } 

Adja hozzá a Description-t a CustomValidationForm összetevő űrlapjához.

<InputText @bind-Value="Model!.Description" />

Frissítse a EditContext példányt az összetevő OnInitialized metódusában az új mező CSS-osztályszolgáltató használatára:

editContext?.SetFieldCssClassProvider(new CustomFieldClassProvider2());

Mivel egy CSS-érvényesítési osztály nincs alkalmazva a Description mezőre, az nincs formázva. A mezőérvényesítés azonban normálisan fut. Ha több mint 10 karakter van megadva, az érvényesítési összegzés a következő hibát jelzi:

A leírás túl hosszú.

Az alábbi példában:

  • Az egyéni CSS-stílus a Name mezőre lesz alkalmazva.

  • Minden más mező az Blazoralapértelmezett logikáját és a Blazoralapértelmezett CSS-érvényesítési stílusait alkalmazza, a modified-t a valid-mal vagy a invalid-gyel együtt. Vegye figyelembe, hogy az alapértelmezett stílusokhoz nem kell hozzáadnia őket az alkalmazás stíluslapjára, ha az alkalmazás egy Blazor projektsablonon alapul. A nem Blazor projektsablonon alapuló alkalmazások esetében az alapértelmezett stílusok hozzáadhatók az alkalmazás stíluslapjára:

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

Frissítse a EditContext példányt az összetevő OnInitialized metódusában az előző mező CSS-osztályszolgáltatójának használatára:

editContext.SetFieldCssClassProvider(new CustomFieldClassProvider3());

A CustomFieldClassProvider3használata:

  • A Name mező az alkalmazás egyéni érvényesítési CSS-stílusait használja.
  • A Description mező a Blazorlogikájára és Blazoralapértelmezett csS-érvényesítési stílusára hasonlító logikát használ.

Osztályszintű ellenőrzés IValidatableObject

osztályszintű ellenőrzés IValidatableObject (API dokumentáció) támogatott a Blazor űrlapmodellek esetében. IValidatableObject érvényesítés csak az űrlap elküldésekor, és csak akkor, ha az összes többi ellenőrzés sikeres.

Blazor adatjegyzetek érvényesítési csomagja

Jegyzet

A Microsoft.AspNetCore.Components.DataAnnotations.Validation csomag már nem ajánlott a .NET 10-et vagy újabb verziót célzó alkalmazásokhoz. További információ: Beágyazott objektumok, gyűjteménytípusok és összetett típusok szakasz.

A Microsoft.AspNetCore.Components.DataAnnotations.Validation csomag kitölti az ellenőrzési felület hiányosságait az DataAnnotationsValidator összetevő használatával. A csomag jelenleg kísérleti.

Figyelmeztetés

A Microsoft.AspNetCore.Components.DataAnnotations.Validation csomag a kiadásra jelölt legújabb verzióval rendelkezik a NuGet.org. Továbbra is használja a kísérleti kiadásra jelölt csomagot. A kísérleti funkciók a funkciók életképességének feltárására szolgálnak, és nem szállíthatók stabil verzióban. További frissítésekért tekintse meg a Közlemények GitHub-adattárát, a dotnet/aspnetcore GitHub-adattárat, vagy ezt a témakört.

[CompareProperty] attribútum

A CompareAttribute nem működik megfelelően a DataAnnotationsValidator összetevővel, mert a DataAnnotationsValidator nem társítja az érvényesítési eredményt egy adott taggal. Ez inkonzisztens működést eredményezhet a mezőszintű ellenőrzés és a teljes modell elküldésekor. A Microsoft.AspNetCore.Components.DataAnnotations.Validationkísérleti csomag egy további érvényesítési attribútumot vezet be, ComparePropertyAttributeamely megkerüli ezeket a korlátozásokat. Egy Blazor alkalmazásban a [CompareProperty] a [Compare] attribútum közvetlen helyettesítője.

Beágyazott objektumok és gyűjteménytípusok

Blazor Az űrlap érvényesítése magában foglalja a beágyazott objektumok és a gyűjteményelemek tulajdonságainak érvényesítését a beépített DataAnnotationsValidator.

Érvényesített űrlap létrehozásához használjon egy DataAnnotationsValidator összetevőt egy EditForm összetevőn belül, ugyanúgy, mint korábban.

A beágyazott objektumok és gyűjteménytípusok érvényesítési funkciójának engedélyezése:

  1. Hívja meg a AddValidation bővítménymetódust abban a fájlban, amelyben a Program szolgáltatások regisztrálva vannak.
  2. Deklarálja az űrlapmodell-típusokat egy C#-osztályfájlban, nem egy Razor összetevőben (.razor).
  3. Jelölje meg az alapmodell típusát az [ValidatableType] attribútummal.

Az előző lépések követése nélkül az űrlapérvényesítési viselkedés nem foglalja magában a beágyazott modell és a gyűjteménytípus érvényesítését.

Az alábbi példa a továbbfejlesztett űrlap-ellenőrzéssel rendelkező ügyfélrendeléseket mutatja be (a rövidség kedvéért kihagyott részletek):

A Program.cs-ban a AddValidation meghívása a szolgáltatási gyűjteményen.

builder.Services.AddValidation();

A következő Order osztályban az [ValidatableType] attribútum szükséges a felső szintű modelltípushoz. A többi típust a rendszer automatikusan felderíti. OrderItem és ShippingAddress nem jelennek meg a rövidség kedvéért, de a beágyazott és gyűjteményérvényesítés ugyanúgy működik ezekben a típusokban, ha azok megjelennek.

Order.cs:

using System.ComponentModel.DataAnnotations;

[ValidatableType]
public class Order
{
    public Customer Customer { get; set; } = new();
    public List<OrderItem> OrderItems { get; set; } = [];
}

public class Customer
{
    [Required(ErrorMessage = "Name is required.")]
    public string? FullName { get; set; }

    [Required(ErrorMessage = "Email is required.")]
    public string? Email { get; set; }

    public ShippingAddress ShippingAddress { get; set; } = new();
}

A következő OrderPage összetevőben az DataAnnotationsValidator összetevő jelen van az EditForm összetevőben.

OrderPage.razor:

<EditForm Model="Model">
    <DataAnnotationsValidator />

    <h3>Customer Details</h3>
    <div class="mb-3">
        <label>
            Full Name
            <InputText @bind-Value="Model!.Customer.FullName" />
        </label>
        <ValidationMessage For="@(() => Model!.Customer.FullName)" />
    </div>

    // ... form continues ...
</EditForm>

@code {
    public Order? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();
}

A modelltípusok összetevőkön (Razorfájlokon) kívüli deklarálásának .razor követelménye annak a ténynek köszönhető, hogy az új érvényesítési funkció és maga a Razor fordító is egy forrásgenerátort használ. Jelenleg az egyik forrásgenerátor kimenete nem használható bemenetként egy másik forrásgenerátorhoz.

Egy másik szerelvény érvényesítési modelljeinek használatáról a másik szerelvényből származó érvényesítési modellek használata című szakaszban talál útmutatást.

Beágyazott objektumok, gyűjteménytípusok és összetett típusok

Jegyzet

A .NET 10-es vagy újabb verzióját célzó alkalmazások esetében a továbbiakban nem javasoljuk az ebben a Microsoft.AspNetCore.Components.DataAnnotations.Validation szakaszban ismertetett kísérleti csomag és megközelítés használatát. Javasoljuk, hogy használja az összetevő beépített érvényesítési funkcióit DataAnnotationsValidator .

Blazor támogatja az űrlapbemenetek adatjegyzetekkel való érvényesítését a beépített DataAnnotationsValidator. A DataAnnotationsValidator .NET 9-es vagy korábbi verziójában azonban csak az űrlaphoz kötött modell legfelső szintű tulajdonságait ellenőrzi, amelyek nem gyűjtemény- vagy összetett típusú tulajdonságok.

A kötött modell teljes objektumgráfjának ellenőrzéséhez, beleértve a gyűjtemény- és összetett típusú tulajdonságokat, használja a ObjectGraphDataAnnotationsValidatorkísérletiMicrosoft.AspNetCore.Components.DataAnnotations.Validation csomag által a .NET 9-ben vagy korábbi verzióiban megadott adatokat:

<EditForm ...>
    <ObjectGraphDataAnnotationsValidator />
    ...
</EditForm>

A modelltulajdonságokat jelöljük [ValidateComplexType]-val. A következő modellosztályokban a ShipDescription osztály további adatjegyzeteket tartalmaz annak ellenőrzéséhez, hogy a modell mikor van az űrlaphoz kötve:

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

Más szerelvény érvényesítési modelljeinek használata

Egy külön álló összeállításban, például egy könyvtárban vagy egy .Client projektben definiált Blazor Web App modellérvényesítéshez:

  • Ha a kódtár egyszerű osztálytár (nem az Microsoft.NET.Sdk.WebMicrosoft.NET.Sdk.Razor SDK-kon alapul), adjon hozzá egy csomaghivatkozást a Microsoft.Extensions.Validation NuGet-csomag kódtárához. Az egyszerű osztálykódtárakhoz további lépések szükségesek, amelyeket a szakasz későbbi részében ismertetünk.
  • Hozzon létre egy metódust a tárban vagy .Client projektben, amely argumentumként fogad egy IServiceCollection példányt, és meghívja AddValidation azt.
  • Az alkalmazásban hívja meg a metódust és AddValidation.

Az előző megközelítés mindkét szerelvények típusának ellenőrzését eredményezi.

Az alábbi példában a AddValidationForTypesInClient metódus létrejön a .Client projekt Blazor Web App keretében, a .Client projektben meghatározott típusokat használva, az ellenőrzéshez.

ServiceCollectionExtensions.cs (.Client projektben)

namespace BlazorSample.Client.Extensions;

public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddValidationForTypesInClient(
        this IServiceCollection collection)
    {
        return collection.AddValidation();
    }
}

A szerverprojekt fájljában Program, adja hozzá a névteret, és hívja meg a .Client projekt szolgáltatásgyűjteményének bővítési metódusát (AddValidationForTypesInClient) és AddValidation.

using BlazorSample.Client.Extensions;

...

builder.Services.AddValidationForTypesInClient();
builder.Services.AddValidation();

A csomag új attribútumai Microsoft.Extensions.Validation (ValidatableTypeAttribute és SkipValidationAttribute) kísérletiként jelennek meg a .NET 10-ben. A csomag célja, hogy új megosztott infrastruktúrát biztosítson a keretrendszerek érvényesítési funkcióihoz, és a kísérleti típusok közzététele nagyobb rugalmasságot biztosít a nyilvános API végső kialakításához, hogy jobban támogassa a keretrendszerek használatát.

Az alkalmazásokban Blazor a típusok egy létrehozott beágyazott attribútumon keresztül érhetők el. Ha egy Microsoft.NET.Sdk.Web SDK-t (<Project Sdk="Microsoft.NET.Sdk.Web">) használó webalkalmazás-projekt vagy egy Microsoft.NET.Sdk.Razor SDK-t (<Project Sdk="Microsoft.NET.Sdk.Razor">) használó RCL Razor összetevőket (.razor) tartalmaz, a keretrendszer automatikusan létrehoz egy belső attribútumot a projekten belül (Microsoft.Extensions.Validation.Embedded.ValidatableType, Microsoft.Extensions.Validation.Embedded.SkipValidation). Ezek a típusok felcserélhetők a tényleges attribútumokkal, és nem kísérleti jellegűek. Az esetek többségében a fejlesztők az [ValidatableType]/[SkipValidation] osztályaik attribútumait használják anélkül, hogy aggódnak a forrásuk miatt.

Az előző megközelítés azonban nem járható út az Microsoft.NET.Sdk SDK-t (<Project Sdk="Microsoft.NET.Sdk">) használó egyszerű osztálykódtárakban. Az egyszerű osztálykódtárak típusainak használata kódelemzési figyelmeztetést eredményez:

ASP0029: A "Microsoft.Extensions.Validation.ValidatableTypeAttribute" csak kiértékelésre szolgál, és a jövőbeli frissítésekben változhat vagy eltávolítható. A folytatáshoz tiltsa le ezt a diagnosztikát.

A figyelmeztetés az alábbi módszerek bármelyikével mellőzhető:

  • A <NoWarn> projektfájl egyik tulajdonsága:

    <PropertyGroup>
      <NoWarn>$(NoWarn);ASP0029</NoWarn>
    </PropertyGroup>
    
  • Egy pragma irányelv , amelyben az attribútumot használják:

    #pragma warning disable ASP0029
    [Microsoft.Extensions.Validation.ValidatableType]
    #pragma warning restore ASP0029
    
  • Egy EditorConfig-fájl (.editorconfig) szabály:

    dotnet_diagnostic.ASP0029.severity = none
    

Ha a figyelmeztetés mellőzése nem elfogadható, manuálisan hozza létre a beágyazott attribútumot a webes és Razor SDK-k által automatikusan létrehozott kódtárban.

ValidatableTypeAttribute.cs:

namespace Microsoft.Extensions.Validation.Embedded
{
    [AttributeUsage(AttributeTargets.Class)]
    internal sealed class ValidatableTypeAttribute : Attribute
    {
    }
}

Használja a pontos névteret (Microsoft.Extensions.Validation.Embedded) és osztálynevet (ValidatableTypeAttribute) annak érdekében, hogy az érvényesítési forrásgenerátor észlelje és használja a típust. A névtér számára globálisan deklarálhat egy using utasítást, vagy egy global using Microsoft.Extensions.Validation.Embedded; utasítást, vagy egy <Using Include="Microsoft.Extensions.Validation.Embedded" /> elemet a könyvtár projektfájljában.

Bármelyik megközelítést is alkalmazza, a kód későbbi frissítéséhez használt kerülő megoldás meglétét kell jelölnie. A .NET 11-hez (2026. november) tervezik az ellenőrzési típusok egyszerű osztálykódtárakban való bevezetését megkönnyítő keretrendszerfrissítéseket.

A küldés gomb engedélyezése űrlapérvényesítés alapján

A küldés gomb űrlapérvényesítésen alapuló engedélyezéséhez és letiltásához kövesse az alábbi példát:

  • A Starfleet Starship Database cikk Starship3 szakaszának korábbi űrlapjának ( összetevőjének) rövidített verzióját használja, amely csak a hajóazonosító értékét fogadja el. A többi Starship tulajdonság érvényes alapértelmezett értékeket kap a Starship típusú példány létrehozásakor.
  • A modellt a EditContext azonosítójú űrlap használatával rendeli hozzá, amikor az összetevő inicializálódik.
  • A OnFieldChanged visszahívás környezetében ellenőrzi az űrlapot, hogy engedélyezze és letiltsa a küldési gombot.
  • Implementálja IDisposable és leiratkozza az eseménykezelőt a Dispose metódusban. További információért lásd: ASP.NET Core Razor összetevők kezelése vagy eltávolítása.

Jegyzet

Amikor EditForm.EditContext-hoz rendel, ne rendeljen EditForm.Model-et egyidejűleg a EditForm-höz is.

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

Ha egy űrlap nincs előre betöltve érvényes értékekkel, és le szeretné tiltani a Submit gombot az űrlap betöltésekor, állítsa formInvalidtrueértékre.

Az előző megközelítés egyik mellékhatása, hogy az érvényesítési összegzés (ValidationSummary összetevő) érvénytelen mezőkkel van feltöltve, miután a felhasználó egy mezővel kommunikál. Ezt a forgatókönyvet az alábbi módokon oldhatja meg:

  • Ne használjon ValidationSummary összetevőt az űrlapon.
  • Tegye láthatóvá a ValidationSummary összetevőt a Küldés gomb kiválasztásakor (például egy Submit metódusban).
<EditForm ... EditContext="editContext" OnValidSubmit="Submit" ...>
    <DataAnnotationsValidator />
    <ValidationSummary style="@displaySummary" />

    ...

    <button type="submit" disabled="@formInvalid">Submit</button>
</EditForm>

@code {
    private string displaySummary = "display:none";

    ...

    private void Submit()
    {
        displaySummary = "display:block";
    }
}

DataAnnotationsValidator érvényesítési viselkedés

Az DataAnnotationsValidator összetevő ugyanolyan érvényesítési sorrendben és rövidzárolási viselkedéssel rendelkezik, mint a System.ComponentModel.DataAnnotations.Validator. A rendszer a következő szabályokat alkalmazza egy típuspéldány Tellenőrzésekor:

  1. A rendszer ellenőrzi a T tagok tulajdonságait, beleértve a beágyazott objektumok rekurzív érvényesítését is.
  2. A rendszer ellenőrzi a T típusszintű attribútumokat.
  3. A IValidatableObject.Validate metódus végrehajtása akkor történik meg, ha T implementálja.

Ha az előző lépések egyike érvényesítési hibát eredményez, a rendszer kihagyja a többi lépést.