Ověření modelu v ASP.NET Core MVC a Razor stránkách

Tento článek vysvětluje, jak ověřit vstup uživatele v aplikaci ASP.NET Core MVC nebo Razor Pages.

Zobrazení nebo stažení vzorového kódu (postup stažení)

Stav modelu

Stav modelu představuje chyby, které pocházejí ze dvou subsystémů: vazby modelu a ověření modelu. Chyby, které pocházejí z vazby modelu , jsou obecně chyby převodu dat. Například "x" je zadán do celočíselného pole. K ověření modelu dochází po vazbě modelu a hlásí chyby, kdy data neodpovídají obchodním pravidlům. Například 0 je zadáno v poli, které očekává hodnocení od 1 do 5.

Před provedením akce kontroleru nebo Razor metody obslužné rutiny Pages dochází k vazbě modelu i ověření modelu. U webových aplikací je tato aplikace zodpovědná za to, že kontroluje ModelState.IsValid a reaguje odpovídajícím způsobem. Webové aplikace obvykle znovu zobrazí stránku s chybovou zprávou, jak je znázorněno v následujícím Razor příkladu stránek:

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    _context.Movies.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

Pro ASP.NET Core MVC s kontrolery a zobrazeními ukazuje následující příklad, jak zkontrolovat ModelState.IsValid uvnitř akce kontroleru:

public async Task<IActionResult> Create(Movie movie)
{
    if (!ModelState.IsValid)
    {
        return View(movie);
    }

    _context.Movies.Add(movie);
    await _context.SaveChangesAsync();

    return RedirectToAction(nameof(Index));
}

Kontrolery webového rozhraní API nemusí zkontrolovatModelState.IsValid, jestli mají atribut [ApiController]. V takovém případě se vrátí automatická odpověď HTTP 400 obsahující podrobnosti o chybě, když je stav modelu neplatný. Další informace naleznete v tématu Automatické odpovědi HTTP 400.

Znovu spustit ověření

Ověření je automatické, ale možná ho budete chtít opakovat ručně. Můžete například vypočítat hodnotu vlastnosti a po nastavení vlastnosti na vypočítanou hodnotu znovu spustit ověření. Pokud chcete znovu spustit ověření, zavolejte ModelStateDictionary.ClearValidationState ověření specifické pro model, za nímž TryValidateModelnásleduje:

public async Task<IActionResult> OnPostTryValidateAsync()
{
    var modifiedReleaseDate = DateTime.Now.Date;
    Movie.ReleaseDate = modifiedReleaseDate;

    ModelState.ClearValidationState(nameof(Movie));
    if (!TryValidateModel(Movie, nameof(Movie)))
    {
        return Page();
    }

    _context.Movies.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

Ověřovací atributy

Ověřovací atributy umožňují zadat ověřovací pravidla pro vlastnosti modelu. Následující příklad z ukázkové aplikace ukazuje třídu modelu, která je opatřena poznámkami ověřovacími atributy. Atribut [ClassicMovie] je vlastní ověřovací atribut a ostatní jsou integrované. Nezobrazuje se [ClassicMovieWithClientValidator], což ukazuje alternativní způsob implementace vlastního atributu.

public class Movie
{
    public int Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Title { get; set; } = null!;

    [ClassicMovie(1960)]
    [DataType(DataType.Date)]
    [Display(Name = "Release Date")]
    public DateTime ReleaseDate { get; set; }

    [Required]
    [StringLength(1000)]
    public string Description { get; set; } = null!;

    [Range(0, 999.99)]
    public decimal Price { get; set; }

    public Genre Genre { get; set; }

    public bool Preorder { get; set; }
}

Předdefinované atributy

Tady jsou některé předdefinované ověřovací atributy:

  • [ValidateNever]: Označuje, že vlastnost nebo parametr by měly být vyloučeny z ověření.
  • [Kreditní karta]: Ověří, že vlastnost má formát platební karty. Vyžaduje ověření jQuery Další metody.
  • [Porovnat]: Ověří, že dvě vlastnosti v modelu odpovídají.
  • [EmailAddress]: Ověří, jestli má vlastnost formát e-mailu.
  • [Telefon]: Ověří, že vlastnost má formát telefonního čísla.
  • [Rozsah]: Ověří, že hodnota vlastnosti spadá do zadaného rozsahu.
  • [RegularExpression]: Ověřuje, že hodnota vlastnosti odpovídá zadanému regulárnímu výrazu.
  • [Povinné]: Ověří, že pole nemá hodnotu null. Podrobnosti [Required] o chování tohoto atributu najdete v atributu.
  • [StringLength]: Ověří, že hodnota vlastnosti řetězce nepřekračuje zadaný limit délky.
  • [Url]: Ověří, že vlastnost má formát adresy URL.
  • [Vzdálený]: Ověří vstup klienta voláním metody akce na serveru. Podrobnosti [Remote] o chování tohoto atributu najdete v atributu.

Úplný seznam ověřovacích atributů najdete v System.ComponentModel.DataAnnotations oboru názvů.

Chybové zprávy

Ověřovací atributy umožňují zadat chybovou zprávu, která se má zobrazit pro neplatný vstup. Příklad:

[StringLength(8, ErrorMessage = "Name length can't be more than 8.")]

Atributy volají String.Format interně zástupný symbol pro název pole a někdy i další zástupné symboly. Příklad:

[StringLength(8, ErrorMessage = "{0} length must be between {2} and {1}.", MinimumLength = 6)]

Při použití u Name vlastnosti by chybová zpráva vytvořená předchozím kódem byla "Délka názvu musí být v rozsahu 6 až 8".

Pokud chcete zjistit, které parametry se předávají String.Format pro chybovou zprávu konkrétního atributu, přečtěte si zdrojový kód DataAnnotations.

Odkazové typy bez hodnoty null a atribut [Povinné]

Ověřovací systém zpracovává parametry bez hodnoty null nebo vázané vlastnosti, jako by měly [Required(AllowEmptyStrings = true)] atribut. Když povolíte Nullable kontexty, MVC implicitně začne ověřovat nenulovatelné vlastnosti nebo parametry, jako by byly přiřazeny atributem [Required(AllowEmptyStrings = true)] . Vezměme si následující kód:

public class Person
{
    public string Name { get; set; }
}

Pokud byla aplikace sestavena s <Nullable>enable</Nullable>chybějící hodnotou v NameJSon nebo formuláři, výsledkem je chyba ověření. Pokud chcete povolit zadání hodnot null nebo chybějících hodnot pro vlastnost, použijte typ odkazu s možnou Name hodnotou null:

public class Person
{
    public string? Name { get; set; }
}

Toto chování je možné zakázat konfigurací SuppressImplicitRequiredAttributeForNonNullableReferenceTypes v :Program.cs

builder.Services.AddControllers(
    options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true);

Odkazové typy bez hodnoty null a atribut [Povinné]

Ověřovací systém zpracovává parametry bez hodnoty null nebo vázané vlastnosti, jako by měly [Required(AllowEmptyStrings = true)] atribut. Když povolíte Nullable kontexty, MVC implicitně spustí ověřování nenulovatelných vlastností u jiných než obecných typů nebo parametrů, jako by byly přiřazeny atributem [Required(AllowEmptyStrings = true)] . Vezměme si následující kód:

public class Person
{
    public string Name { get; set; }
}

Pokud byla aplikace sestavena s <Nullable>enable</Nullable>chybějící hodnotou v NameJSon nebo formuláři, výsledkem je chyba ověření. Pokud chcete povolit zadání hodnot null nebo chybějících hodnot pro vlastnost, použijte typ odkazu s možnou Name hodnotou null:

public class Person
{
    public string? Name { get; set; }
}

Toto chování je možné zakázat konfigurací SuppressImplicitRequiredAttributeForNonNullableReferenceTypes v :Program.cs

builder.Services.AddControllers(
    options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true);

Vlastnosti bez hodnoty null u obecných typů a atribut [Povinné]

Vlastnosti, které nemají hodnotu null u obecných typů, musí obsahovat [Required] atribut, pokud je typ povinný. V následujícím kódu TestRequired se nevyžaduje:

public class WeatherForecast<T>
{
    public string TestRequired { get; set; } = null!;
    public T? Inner { get; set; }
}

V následujícím kódu TestRequired se explicitně označí jako povinné:

using System.ComponentModel.DataAnnotations;

public class WeatherForecast<T>
{
    [Required]
    public string TestRequired { get; set; } = null!;
    public T? Inner { get; set; }
}

[Požadováno] Ověření na serveru

Na serveru se požadovaná hodnota považuje za chybějící, pokud je vlastnost null. Pole, které nemá hodnotu null, je vždy platné a chybová zpráva atributu [Required] se nikdy nezobrazí.

Vazba modelu pro vlastnost bez hodnoty null však může selhat, což vede k chybové zprávě, například The value '' is invalid. Pokud chcete zadat vlastní chybovou zprávu pro ověřování typů, které nemají hodnotu null, máte následující možnosti:

  • Nastavit pole jako null (například decimal? místo decimal). Nullable< Typy hodnot T> se považují za standardní typy s možnou hodnotou null.

  • Zadejte výchozí chybovou zprávu, kterou má použít vazba modelu, jak je znázorněno v následujícím příkladu:

    builder.Services.AddRazorPages()
        .AddMvcOptions(options =>
        {
            options.MaxModelValidationErrors = 50;
            options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
                _ => "The field is required.");
        });
    
    builder.Services.AddSingleton
        <IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
    

    Další informace o chybách vazby modelu, pro které můžete nastavit výchozí zprávy, naleznete v tématu DefaultModelBindingMessageProvider.

[Požadováno] Ověření v klientovi

Typy a řetězce, které nemají hodnotu null, se na klientovi zpracovávají jinak než na serveru. Na klientovi:

  • Hodnota je považována za současnou pouze v případě, že je pro ni zadán vstup. Ověření na straně klienta proto zpracovává typy bez hodnoty null stejné jako typy s možnou hodnotou null.
  • Prázdné znaky v řetězcovém poli se považují za platný vstup požadovanou metodou jQuery Validation. Ověření na straně serveru považuje povinné pole řetězce za neplatné, pokud je zadáno pouze prázdné znaky.

Jak jsme si poznamenali dříve, typy, které nemají hodnotu null, se považují [Required(AllowEmptyStrings = true)] za atributy. To znamená, že získáte ověření na straně klienta, i když atribut nepoužijete [Required(AllowEmptyStrings = true)] . Pokud ale atribut nepoužíváte, zobrazí se výchozí chybová zpráva. Pokud chcete zadat vlastní chybovou zprávu, použijte atribut.

[Vzdálený] atribut

Atribut [Remote] implementuje ověření na straně klienta, které vyžaduje volání metody na serveru k určení, zda je vstup pole platný. Aplikace může například muset ověřit, jestli se už používá uživatelské jméno.

Implementace vzdáleného ověřování:

  1. Vytvořte metodu akce pro volání JavaScriptu. Vzdálená metoda ověřování jQuery očekává JSodpověď ON:

    • true znamená, že vstupní data jsou platná.
    • false, undefinednebo null znamená, že vstup je neplatný. Zobrazí výchozí chybovou zprávu.
    • Jakýkoli jiný řetězec znamená, že vstup je neplatný. Zobrazí řetězec jako vlastní chybovou zprávu.

    Tady je příklad metody akce, která vrací vlastní chybovou zprávu:

    [AcceptVerbs("GET", "POST")]
    public IActionResult VerifyEmail(string email)
    {
        if (!_userService.VerifyEmail(email))
        {
            return Json($"Email {email} is already in use.");
        }
    
        return Json(true);
    }
    
  2. Ve třídě modelu označte vlastnost atributem [Remote] , který odkazuje na metodu akce ověření, jak je znázorněno v následujícím příkladu:

    [Remote(action: "VerifyEmail", controller: "Users")]
    public string Email { get; set; } = null!;
    

Další pole

Vlastnost AdditionalFields atributu [Remote] umožňuje ověřit kombinace polí s daty na serveru. Pokud by například User model měl FirstName a LastName měl vlastnosti, můžete chtít ověřit, že tento pár názvů už nemají žádní stávající uživatelé. Následující příklad ukazuje, jak použít AdditionalFields:

[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(LastName))]
[Display(Name = "First Name")]
public string FirstName { get; set; } = null!;

[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(FirstName))]
[Display(Name = "Last Name")]
public string LastName { get; set; } = null!;

AdditionalFields lze nastavit explicitně na řetězce "FirstName" a "LastName", ale použití operátoru nameof zjednodušuje pozdější refaktoring. Metoda akce pro toto ověření musí přijímat oba firstName i lastName argumenty:

[AcceptVerbs("GET", "POST")]
public IActionResult VerifyName(string firstName, string lastName)
{
    if (!_userService.VerifyName(firstName, lastName))
    {
        return Json($"A user named {firstName} {lastName} already exists.");
    }

    return Json(true);
}

Když uživatel zadá křestní jméno nebo příjmení, JavaScript provede vzdálené volání, aby zjistil, jestli byla tato dvojice jmen přijata.

Pokud chcete ověřit dvě nebo více dalších polí, zadejte je jako seznam oddělený čárkami. Pokud chcete například přidat MiddleName vlastnost do modelu, nastavte [Remote] atribut, jak je znázorněno v následujícím příkladu:

[Remote(action: "VerifyName", controller: "Users",
    AdditionalFields = nameof(FirstName) + "," + nameof(LastName))]
public string MiddleName { get; set; }

AdditionalFields, stejně jako všechny argumenty atributů, musí být konstantní výraz. Proto nepoužívejte interpolovaný řetězec ani volání Join k inicializaci AdditionalFields.

Alternativy předdefinovaných atributů

Pokud potřebujete ověření, které neposkytuje předdefinované atributy, můžete:

Vlastní atributy

Pro scénáře, které předdefinované ověřovací atributy nezpracují, můžete vytvořit vlastní ověřovací atributy. Vytvořte třídu, která dědí z ValidationAttribute, a přepsat metodu IsValid .

Metoda IsValid přijímá objekt pojmenovanou hodnotu, což je vstup, který se má ověřit. Přetížení také přijímá ValidationContext objekt, který poskytuje další informace, například instanci modelu vytvořenou vazbou modelu.

Následující příklad ověří, že datum vydání filmu v klasickém žánru není pozdější než zadaný rok. Atribut [ClassicMovie] :

  • Běží jenom na serveru.
  • U klasických filmů ověří datum vydání:
public class ClassicMovieAttribute : ValidationAttribute
{
    public ClassicMovieAttribute(int year)
        => Year = year;

    public int Year { get; }

    public string GetErrorMessage() =>
        $"Classic movies must have a release year no later than {Year}.";

    protected override ValidationResult? IsValid(
        object? value, ValidationContext validationContext)
    {
        var movie = (Movie)validationContext.ObjectInstance;
        var releaseYear = ((DateTime)value!).Year;

        if (movie.Genre == Genre.Classic && releaseYear > Year)
        {
            return new ValidationResult(GetErrorMessage());
        }

        return ValidationResult.Success;
    }
}

movie Proměnná v předchozím příkladu představuje Movie objekt, který obsahuje data z odeslání formuláře. Pokud ověření selže, ValidationResult vrátí se chybová zpráva.

IValidatableObject

Předchozí příklad funguje jenom s Movie typy. Další možností ověření na úrovni třídy je implementace IValidatableObject ve třídě modelu, jak je znázorněno v následujícím příkladu:

public class ValidatableMovie : IValidatableObject
{
    private const int _classicYear = 1960;

    public int Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Title { get; set; } = null!;

    [DataType(DataType.Date)]
    [Display(Name = "Release Date")]
    public DateTime ReleaseDate { get; set; }

    [Required]
    [StringLength(1000)]
    public string Description { get; set; } = null!;

    [Range(0, 999.99)]
    public decimal Price { get; set; }

    public Genre Genre { get; set; }

    public bool Preorder { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (Genre == Genre.Classic && ReleaseDate.Year > _classicYear)
        {
            yield return new ValidationResult(
                $"Classic movies must have a release year no later than {_classicYear}.",
                new[] { nameof(ReleaseDate) });
        }
    }
}

Ověření uzlu nejvyšší úrovně

Mezi uzly nejvyšší úrovně patří:

  • Parametry akce
  • Vlastnosti kontroleru
  • Parametry obslužné rutiny stránky
  • Vlastnosti modelu stránky

Uzly nejvyšší úrovně vázané na model se ověřují kromě ověřování vlastností modelu. V následujícím příkladu z ukázkové aplikaceVerifyPhone metoda použije RegularExpressionAttribute k ověření parametru phone akce:

[AcceptVerbs("GET", "POST")]
public IActionResult VerifyPhone(
    [RegularExpression(@"^\d{3}-\d{3}-\d{4}$")] string phone)
{
    if (!ModelState.IsValid)
    {
        return Json($"Phone {phone} has an invalid format. Format: ###-###-####");
    }

    return Json(true);
}

Uzly nejvyšší úrovně můžou používat BindRequiredAttribute s ověřovacími atributy. V následujícím příkladu z ukázkové aplikace metoda určuje, CheckAge že age parametr musí být při odeslání formuláře vázán z řetězce dotazu:

[HttpPost]
public IActionResult CheckAge([BindRequired, FromQuery] int age)
{

Na stránce Kontrola věku (CheckAge.cshtml) existují dva formuláře. První formulář odešle Age hodnotu 99 jako parametr řetězce dotazu: https://localhost:5001/Users/CheckAge?Age=99.

Pokud se odešle správně formátovaný age parametr z řetězce dotazu, formulář se ověří.

Druhý formulář na stránce Kontrola věku odešle Age hodnotu v textu požadavku a ověření selže. Vazba selže, protože age parametr musí pocházet z řetězce dotazu.

Maximální počet chyb

Ověření se zastaví při dosažení maximálního počtu chyb (ve výchozím nastavení 200). Toto číslo můžete nakonfigurovat následujícím kódem v Program.cs:

builder.Services.AddRazorPages()
    .AddMvcOptions(options =>
    {
        options.MaxModelValidationErrors = 50;
        options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
            _ => "The field is required.");
    });

builder.Services.AddSingleton
    <IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();

Maximální rekurz

ValidationVisitor prochází grafem objektů modelu, který se ověřuje. U modelů, které jsou hluboké nebo nekonečně rekurzivní, může ověření vést k přetečení zásobníku. MvcOptions.MaxValidationDepth poskytuje způsob, jak předčasně zastavit ověření, pokud rekurz návštěvník překročí nakonfigurovanou hloubku. Výchozí hodnota MvcOptions.MaxValidationDepth je 32.

Automatický zkrat

Pokud graf modelu nevyžaduje ověření, je ověření automaticky zkrácené (vynecháno). Objekty, které modul runtime přeskočí ověřování, zahrnují kolekce primitivních objektů (například byte[], string[]), Dictionary<string, string>a komplexní objektové grafy, které nemají žádné validátory.

Ověřování na straně klienta

Ověření na straně klienta brání odeslání, dokud formulář není platný. Tlačítko Odeslat spustí JavaScript, který buď odešle formulář, nebo zobrazí chybové zprávy.

Ověřování na straně klienta zabraňuje zbytečnému odezvě na server, pokud ve formuláři dojde k chybám vstupu. Následující odkazy na skripty a _Layout.cshtml_ValidationScriptsPartial.cshtml podporují ověřování na straně klienta:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.3/jquery.validate.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.12/jquery.validate.unobtrusive.js"></script>

Skript jQuery Unobtrusive Validation je vlastní front-end knihovna Microsoftu, která vychází z oblíbeného modulu plug-in jQuery Validation. Bez bezobtěžného ověřování jQuery byste museli kódovat stejnou logiku ověřování na dvou místech: jednou v atributech ověřování na straně serveru ve vlastnostech modelu a pak znovu ve skriptech na straně klienta. Místo toho pomocné rutiny značek a pomocné rutiny HTML používají ověřovací atributy a metadata typu z vlastností modelu k vykreslení atributů HTML 5 data- pro prvky formuláře, které potřebují ověření. jQuery Unobtrusive Validation parsuje data- atributy a předává logiku do jQuery Validation, efektivně "kopírování" logiky ověřování na straně serveru do klienta. Chyby ověřování můžete zobrazit na klientovi pomocí pomocných rutin značek, jak je znázorněno tady:

<div class="form-group">
    <label asp-for="Movie.ReleaseDate" class="control-label"></label>
    <input asp-for="Movie.ReleaseDate" class="form-control" />
    <span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
</div>

Pomocné rutiny předchozích značek vykreslují následující kód HTML:

<div class="form-group">
    <label class="control-label" for="Movie_ReleaseDate">Release Date</label>
    <input class="form-control" type="date" data-val="true"
        data-val-required="The Release Date field is required."
        id="Movie_ReleaseDate" name="Movie.ReleaseDate" value="">
    <span class="text-danger field-validation-valid"
        data-valmsg-for="Movie.ReleaseDate" data-valmsg-replace="true"></span>
</div>

Všimněte si, že data- atributy ve výstupu HTML odpovídají ověřovacím atributům Movie.ReleaseDate vlastnosti. Atribut data-val-required obsahuje chybovou zprávu, která se zobrazí, pokud uživatel nezaplní pole data vydání. jQuery Unobtrusive Validation předá tuto hodnotu metodě jQuery Validation required(), která pak zobrazí tuto zprávu v doprovodném <prvku span> .

Ověření datového typu je založeno na typu .NET vlastnosti, pokud není přepsán atributem [DataType]. Prohlížeče mají vlastní výchozí chybové zprávy, ale balíček jQuery Validation Unobtrusive Validation může tyto zprávy přepsat. [DataType] atributy a podtřídy, jako je [EmailAddress], umožňují zadat chybovou zprávu.

Neobtěžující ověření

Informace o nerušivém ověření najdete v tomto GitHub problému.

Přidání ověření do dynamických formulářů

jQuery Unobtrusive Validation předá ověřovací logiku a parametry do jQuery Validation při prvním načtení stránky. Proto ověřování nefunguje automaticky na dynamicky generovaných formulářích. Pokud chcete povolit ověření, řekněte jQuery Unobtrusive Validation, aby se dynamický formulář parsuje okamžitě po jeho vytvoření. Například následující kód nastaví ověření na straně klienta ve formuláři přidaném přes AJAX.

$.get({
    url: "https://url/that/returns/a/form",
    dataType: "html",
    error: function(jqXHR, textStatus, errorThrown) {
        alert(textStatus + ": Couldn't add form. " + errorThrown);
    },
    success: function(newFormHTML) {
        var container = document.getElementById("form-container");
        container.insertAdjacentHTML("beforeend", newFormHTML);
        var forms = container.getElementsByTagName("form");
        var newForm = forms[forms.length - 1];
        $.validator.unobtrusive.parse(newForm);
    }
})

Metoda $.validator.unobtrusive.parse() přijímá pro svůj jeden argument volič jQuery. Tato metoda říká jQuery Unobtrusive Validation parsovat data- atributy formulářů v rámci tohoto selektoru. Hodnoty těchto atributů se pak předají modulu plug-in jQuery Validation.

Přidání ověření do dynamických ovládacích prvků

Metoda $.validator.unobtrusive.parse() funguje na celém formuláři, ne na jednotlivých dynamicky generovaných ovládacích prvcích, jako <input> je a <select/>. Chcete-li formulář znovu zobrazit, odeberte ověřovací data přidaná při analýze formuláře dříve, jak je znázorněno v následujícím příkladu:

$.get({
    url: "https://url/that/returns/a/control",
    dataType: "html",
    error: function(jqXHR, textStatus, errorThrown) {
        alert(textStatus + ": Couldn't add control. " + errorThrown);
    },
    success: function(newInputHTML) {
        var form = document.getElementById("my-form");
        form.insertAdjacentHTML("beforeend", newInputHTML);
        $(form).removeData("validator")    // Added by jQuery Validation
               .removeData("unobtrusiveValidation");   // Added by jQuery Unobtrusive Validation
        $.validator.unobtrusive.parse(form);
    }
})

Vlastní ověřování na straně klienta

Vlastní ověřování na straně klienta se provádí generováním data- atributů HTML, které pracují s vlastním adaptérem ověřování jQuery. Následující ukázkový kód adaptéru byl napsán pro [ClassicMovie][ClassicMovieWithClientValidator] atributy, které byly zavedeny dříve v tomto článku:

$.validator.addMethod('classicmovie', function (value, element, params) {
    var genre = $(params[0]).val(), year = params[1], date = new Date(value);

    // The Classic genre has a value of '0'.
    if (genre && genre.length > 0 && genre[0] === '0') {
        // The release date for a Classic is valid if it's no greater than the given year.
        return date.getUTCFullYear() <= year;
    }

    return true;
});

$.validator.unobtrusive.adapters.add('classicmovie', ['year'], function (options) {
    var element = $(options.form).find('select#Movie_Genre')[0];

    options.rules['classicmovie'] = [element, parseInt(options.params['year'])];
    options.messages['classicmovie'] = options.message;
});

Informace o zápisu adaptérů najdete v dokumentaci k ověření jQuery.

Použití adaptéru pro dané pole se aktivuje atributy data- , které:

  • Označte pole příznakem jako předmět ověření (data-val="true").
  • Identifikujte název ověřovacího pravidla a text chybové zprávy (například data-val-rulename="Error message.").
  • Zadejte všechny další parametry, které validátor potřebuje (například data-val-rulename-param1="value").

Následující příklad ukazuje data- atributy atributu ukázkové aplikaceClassicMovie :

<input class="form-control" type="date"
    data-val="true"
    data-val-classicmovie="Classic movies must have a release year no later than 1960."
    data-val-classicmovie-year="1960"
    data-val-required="The Release Date field is required."
    id="Movie_ReleaseDate" name="Movie.ReleaseDate" value="">

Jak jsme si poznamenali dříve, pomocné rutiny značek a pomocné rutiny HTML používají k vykreslení data- atributů informace z ověřovacích atributů. Existují dvě možnosti pro psaní kódu, které mají za následek vytvoření vlastních data- atributů HTML:

AtributAdapter pro ověření na straně klienta

Tato metoda vykreslování data- atributů ve formátu HTML se používá ClassicMovie atributem v ukázkové aplikaci. Chcete-li přidat ověření klienta pomocí této metody:

  1. Vytvořte třídu adaptéru atributu pro vlastní ověřovací atribut. Odvození třídy z AttributeAdapterBase<TAttribute>. Vytvořte metodu AddValidation , která přidá data- atributy do vykresleného výstupu, jak je znázorněno v tomto příkladu:

    public class ClassicMovieAttributeAdapter : AttributeAdapterBase<ClassicMovieAttribute>
    {
        public ClassicMovieAttributeAdapter(
            ClassicMovieAttribute attribute, IStringLocalizer? stringLocalizer)
            : base(attribute, stringLocalizer)
        {
    
        }
    
        public override void AddValidation(ClientModelValidationContext context)
        {
            MergeAttribute(context.Attributes, "data-val", "true");
            MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage(context));
    
            var year = Attribute.Year.ToString(CultureInfo.InvariantCulture);
            MergeAttribute(context.Attributes, "data-val-classicmovie-year", year);
        }
    
        public override string GetErrorMessage(ModelValidationContextBase validationContext)
            => Attribute.GetErrorMessage();
    }
    
  2. Vytvořte třídu zprostředkovatele adaptéru, která implementuje IValidationAttributeAdapterProvider. GetAttributeAdapter V metodě předejte vlastní atribut konstruktoru adaptéru, jak je znázorněno v tomto příkladu:

    public class CustomValidationAttributeAdapterProvider : IValidationAttributeAdapterProvider
    {
        private readonly IValidationAttributeAdapterProvider baseProvider =
            new ValidationAttributeAdapterProvider();
    
        public IAttributeAdapter? GetAttributeAdapter(
            ValidationAttribute attribute, IStringLocalizer? stringLocalizer)
        {
            if (attribute is ClassicMovieAttribute classicMovieAttribute)
            {
                return new ClassicMovieAttributeAdapter(classicMovieAttribute, stringLocalizer);
            }
    
            return baseProvider.GetAttributeAdapter(attribute, stringLocalizer);
        }
    }
    
  3. Registrace zprostředkovatele adaptéru pro DI v:Program.cs

    builder.Services.AddRazorPages()
        .AddMvcOptions(options =>
        {
            options.MaxModelValidationErrors = 50;
            options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
                _ => "The field is required.");
        });
    
    builder.Services.AddSingleton
        <IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
    

IClientModelValidator pro ověřování na straně klienta

Tato metoda vykreslování data- atributů ve formátu HTML se používá ClassicMovieWithClientValidator atributem v ukázkové aplikaci. Chcete-li přidat ověření klienta pomocí této metody:

  • Ve vlastním ověřovacím atributu IClientModelValidator implementujte rozhraní a vytvořte metodu AddValidation . AddValidation V metodě přidejte data- atributy pro ověření, jak je znázorněno v následujícím příkladu:

    public class ClassicMovieWithClientValidatorAttribute :
        ValidationAttribute, IClientModelValidator
    {
        public ClassicMovieWithClientValidatorAttribute(int year)
            => Year = year;
    
        public int Year { get; }
    
        public void AddValidation(ClientModelValidationContext context)
        {
            MergeAttribute(context.Attributes, "data-val", "true");
            MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage());
    
            var year = Year.ToString(CultureInfo.InvariantCulture);
            MergeAttribute(context.Attributes, "data-val-classicmovie-year", year);
        }
    
        public string GetErrorMessage() =>
            $"Classic movies must have a release year no later than {Year}.";
    
        protected override ValidationResult? IsValid(
            object? value, ValidationContext validationContext)
        {
            var movie = (Movie)validationContext.ObjectInstance;
            var releaseYear = ((DateTime)value!).Year;
    
            if (movie.Genre == Genre.Classic && releaseYear > Year)
            {
                return new ValidationResult(GetErrorMessage());
            }
    
            return ValidationResult.Success;
        }
    
        private static bool MergeAttribute(IDictionary<string, string> attributes, string key, string value)
        {
            if (attributes.ContainsKey(key))
            {
                return false;
            }
    
            attributes.Add(key, value);
            return true;
        }
    }
    

Zakázání ověřování na straně klienta

Následující kód zakáže ověření klienta na Razor stránkách:

builder.Services.AddRazorPages()
    .AddViewOptions(options =>
    {
        options.HtmlHelperOptions.ClientValidationEnabled = false;
    });

Další možnosti zakázání ověřování na straně klienta:

  • Zakomentujte odkaz na _ValidationScriptsPartial všechny .cshtml soubory.
  • Odeberte obsah souboru Pages\Shared_ValidationScriptsPartial.cshtml .

Předchozí přístup nezabrání ASP.NET Core IdentityRazor ověření knihovny tříd na straně klienta. Další informace najdete v tématu Generování uživatelského rozhraní Identity v projektech ASP.NET Core.

Další materiály

Tento článek vysvětluje, jak ověřit vstup uživatele v aplikaci ASP.NET Core MVC nebo Razor Pages.

Zobrazení nebo stažení vzorového kódu (postup stažení)

Stav modelu

Stav modelu představuje chyby, které pocházejí ze dvou subsystémů: vazby modelu a ověření modelu. Chyby, které pocházejí z vazby modelu , jsou obecně chyby převodu dat. Například "x" je zadán do celočíselného pole. K ověření modelu dochází po vazbě modelu a hlásí chyby, kdy data neodpovídají obchodním pravidlům. Například 0 je zadáno v poli, které očekává hodnocení od 1 do 5.

Před provedením akce kontroleru nebo Razor metody obslužné rutiny Pages dochází k vazbě modelu i ověření modelu. U webových aplikací je tato aplikace zodpovědná za to, že kontroluje ModelState.IsValid a reaguje odpovídajícím způsobem. Webové aplikace obvykle znovu zobrazí stránku s chybovou zprávou:

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    _context.Movies.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

Kontrolery webového rozhraní API nemusí zkontrolovatModelState.IsValid, jestli mají atribut [ApiController]. V takovém případě se vrátí automatická odpověď HTTP 400 obsahující podrobnosti o chybě, když je stav modelu neplatný. Další informace naleznete v tématu Automatické odpovědi HTTP 400.

Znovu spustit ověření

Ověření je automatické, ale možná ho budete chtít opakovat ručně. Můžete například vypočítat hodnotu vlastnosti a po nastavení vlastnosti na vypočítanou hodnotu znovu spustit ověření. Pokud chcete znovu spustit ověření, zavolejte ModelStateDictionary.ClearValidationState ověření specifické pro model, za nímž TryValidateModelnásleduje:

public async Task<IActionResult> OnPostTryValidateAsync()
{
    var modifiedReleaseDate = DateTime.Now.Date;
    Movie.ReleaseDate = modifiedReleaseDate;

    ModelState.ClearValidationState(nameof(Movie));
    if (!TryValidateModel(Movie, nameof(Movie)))
    {
        return Page();
    }

    _context.Movies.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

Ověřovací atributy

Ověřovací atributy umožňují zadat ověřovací pravidla pro vlastnosti modelu. Následující příklad z ukázkové aplikace ukazuje třídu modelu, která je opatřena poznámkami ověřovacími atributy. Atribut [ClassicMovie] je vlastní ověřovací atribut a ostatní jsou integrované. Nezobrazuje se [ClassicMovieWithClientValidator], což ukazuje alternativní způsob implementace vlastního atributu.

public class Movie
{
    public int Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Title { get; set; }

    [ClassicMovie(1960)]
    [DataType(DataType.Date)]
    [Display(Name = "Release Date")]
    public DateTime ReleaseDate { get; set; }

    [Required]
    [StringLength(1000)]
    public string Description { get; set; }

    [Range(0, 999.99)]
    public decimal Price { get; set; }

    public Genre Genre { get; set; }

    public bool Preorder { get; set; }
}

Předdefinované atributy

Tady jsou některé předdefinované ověřovací atributy:

  • [ValidateNever]: Označuje, že vlastnost nebo parametr by měly být vyloučeny z ověření.
  • [Kreditní karta]: Ověří, že vlastnost má formát platební karty. Vyžaduje ověření jQuery Další metody.
  • [Porovnat]: Ověří, že dvě vlastnosti v modelu odpovídají.
  • [EmailAddress]: Ověří, jestli má vlastnost formát e-mailu.
  • [Telefon]: Ověří, že vlastnost má formát telefonního čísla.
  • [Rozsah]: Ověří, že hodnota vlastnosti spadá do zadaného rozsahu.
  • [RegularExpression]: Ověřuje, že hodnota vlastnosti odpovídá zadanému regulárnímu výrazu.
  • [Povinné]: Ověří, že pole nemá hodnotu null. Podrobnosti [Required] o chování tohoto atributu najdete v atributu.
  • [StringLength]: Ověří, že hodnota vlastnosti řetězce nepřekračuje zadaný limit délky.
  • [Url]: Ověří, že vlastnost má formát adresy URL.
  • [Vzdálený]: Ověří vstup klienta voláním metody akce na serveru. Podrobnosti [Remote] o chování tohoto atributu najdete v atributu.

Úplný seznam ověřovacích atributů najdete v System.ComponentModel.DataAnnotations oboru názvů.

Chybové zprávy

Ověřovací atributy umožňují zadat chybovou zprávu, která se má zobrazit pro neplatný vstup. Příklad:

[StringLength(8, ErrorMessage = "Name length can't be more than 8.")]

Atributy volají String.Format interně zástupný symbol pro název pole a někdy i další zástupné symboly. Příklad:

[StringLength(8, ErrorMessage = "{0} length must be between {2} and {1}.", MinimumLength = 6)]

Při použití u Name vlastnosti by chybová zpráva vytvořená předchozím kódem byla "Délka názvu musí být v rozsahu 6 až 8".

Pokud chcete zjistit, které parametry se předávají String.Format pro chybovou zprávu konkrétního atributu, přečtěte si zdrojový kód DataAnnotations.

Odkazové typy bez hodnoty null a atribut [Povinné]

Ověřovací systém zpracovává parametry bez hodnoty null nebo vázané vlastnosti, jako by měly [Required(AllowEmptyStrings = true)] atribut. Když povolíte Nullable kontexty, MVC implicitně začne ověřovat nenulovatelné vlastnosti nebo parametry, jako by byly přiřazeny atributem [Required(AllowEmptyStrings = true)] . Vezměme si následující kód:

public class Person
{
    public string Name { get; set; }
}

Pokud byla aplikace sestavena s <Nullable>enable</Nullable>chybějící hodnotou v NameJSon nebo formuláři, výsledkem je chyba ověření. Pokud chcete povolit zadání hodnot null nebo chybějících hodnot pro vlastnost, použijte typ odkazu s možnou Name hodnotou null:

public class Person
{
    public string? Name { get; set; }
}

Toto chování je možné zakázat konfigurací SuppressImplicitRequiredAttributeForNonNullableReferenceTypes v :Startup.ConfigureServices

services.AddControllers(options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true);

[Požadováno] Ověření na serveru

Na serveru se požadovaná hodnota považuje za chybějící, pokud je vlastnost null. Pole, které nemá hodnotu null, je vždy platné a chybová zpráva atributu [Required] se nikdy nezobrazí.

Vazba modelu pro vlastnost bez hodnoty null však může selhat, což vede k chybové zprávě, například The value '' is invalid. Pokud chcete zadat vlastní chybovou zprávu pro ověřování typů, které nemají hodnotu null, máte následující možnosti:

  • Nastavit pole jako null (například decimal? místo decimal). Nullable< Typy hodnot T> se považují za standardní typy s možnou hodnotou null.

  • Zadejte výchozí chybovou zprávu, kterou má použít vazba modelu, jak je znázorněno v následujícím příkladu:

    services.AddRazorPages()
        .AddMvcOptions(options =>
        {
            options.MaxModelValidationErrors = 50;
            options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
                _ => "The field is required.");
        });
    
    services.AddSingleton<IValidationAttributeAdapterProvider,
        CustomValidationAttributeAdapterProvider>();
    

    Další informace o chybách vazby modelu, pro které můžete nastavit výchozí zprávy, naleznete v tématu DefaultModelBindingMessageProvider.

[Požadováno] Ověření v klientovi

Typy a řetězce, které nemají hodnotu null, se na klientovi zpracovávají jinak než na serveru. Na klientovi:

  • Hodnota je považována za současnou pouze v případě, že je pro ni zadán vstup. Ověření na straně klienta proto zpracovává typy bez hodnoty null stejné jako typy s možnou hodnotou null.
  • Prázdné znaky v řetězcovém poli se považují za platný vstup požadovanou metodou jQuery Validation. Ověření na straně serveru považuje povinné pole řetězce za neplatné, pokud je zadáno pouze prázdné znaky.

Jak jsme si poznamenali dříve, typy, které nemají hodnotu null, se považují [Required(AllowEmptyStrings = true)] za atributy. To znamená, že získáte ověření na straně klienta, i když atribut nepoužijete [Required(AllowEmptyStrings = true)] . Pokud ale atribut nepoužíváte, zobrazí se výchozí chybová zpráva. Pokud chcete zadat vlastní chybovou zprávu, použijte atribut.

[Vzdálený] atribut

Atribut [Remote] implementuje ověření na straně klienta, které vyžaduje volání metody na serveru k určení, zda je vstup pole platný. Aplikace může například potřebovat ověřit, jestli se už používá uživatelské jméno.

Implementace vzdáleného ověřování:

  1. Vytvořte metodu akce pro volání JavaScriptu. Vzdálená metoda ověřování jQuery očekává JSodpověď ON:

    • true znamená, že vstupní data jsou platná.
    • false, undefinednebo null znamená, že vstup je neplatný. Zobrazí výchozí chybovou zprávu.
    • Jakýkoli jiný řetězec znamená, že vstup je neplatný. Zobrazí řetězec jako vlastní chybovou zprávu.

    Tady je příklad metody akce, která vrací vlastní chybovou zprávu:

    [AcceptVerbs("GET", "POST")]
    public IActionResult VerifyEmail(string email)
    {
        if (!_userService.VerifyEmail(email))
        {
            return Json($"Email {email} is already in use.");
        }
    
        return Json(true);
    }
    
  2. Ve třídě modelu označte vlastnost atributem [Remote] , který odkazuje na metodu ověřovací akce, jak je znázorněno v následujícím příkladu:

    [Remote(action: "VerifyEmail", controller: "Users")]
    public string Email { get; set; }
    

Další pole

Vlastnost AdditionalFields atributu [Remote] umožňuje ověřit kombinace polí s daty na serveru. Pokud například User model měl FirstName a LastName má vlastnosti, můžete chtít ověřit, že tuto dvojici názvů už nemají žádní stávající uživatelé. Následující příklad ukazuje, jak použít AdditionalFields:

[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(LastName))]
[Display(Name = "First Name")]
public string FirstName { get; set; }

[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(FirstName))]
[Display(Name = "Last Name")]
public string LastName { get; set; }

AdditionalFields můžou být explicitně nastaveny na řetězce "FirstName" a "LastName", ale použití nameof operátor zjednodušuje pozdější refaktoring. Metoda akce pro toto ověření musí přijímat oba firstName argumenty lastName :

[AcceptVerbs("GET", "POST")]
public IActionResult VerifyName(string firstName, string lastName)
{
    if (!_userService.VerifyName(firstName, lastName))
    {
        return Json($"A user named {firstName} {lastName} already exists.");
    }

    return Json(true);
}

Když uživatel zadá křestní jméno nebo příjmení, JavaScript provede vzdálené volání, aby zjistil, jestli byla tato dvojice jmen přijata.

Pokud chcete ověřit dvě nebo více dalších polí, zadejte je jako seznam oddělený čárkami. Pokud chcete například přidat MiddleName vlastnost do modelu, nastavte [Remote] atribut, jak je znázorněno v následujícím příkladu:

[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(FirstName) + "," + nameof(LastName))]
public string MiddleName { get; set; }

AdditionalFields, stejně jako všechny argumenty atributů, musí být konstantní výraz. Proto nepoužívejte interpolovaný řetězec ani volání Join k inicializaci AdditionalFields.

Alternativy předdefinovaných atributů

Pokud potřebujete ověření, které neposkytuje předdefinované atributy, můžete:

Vlastní atributy

Ve scénářích, které předdefinované atributy ověřování nezpracují, můžete vytvořit vlastní ověřovací atributy. Vytvořte třídu, která dědí z ValidationAttributea přepíše metodu IsValid .

Metoda IsValid přijímá objekt pojmenovanou hodnotu, což je vstup, který se má ověřit. Přetížení také přijímá ValidationContext objekt, který poskytuje další informace, například instanci modelu vytvořenou vazbou modelu.

Následující příklad ověří, že datum vydání filmu v klasickém žánru není pozdější než zadaný rok. Atribut [ClassicMovie] :

  • Běží jenom na serveru.
  • U klasických filmů ověří datum vydání:
public class ClassicMovieAttribute : ValidationAttribute
{
    public ClassicMovieAttribute(int year)
    {
        Year = year;
    }

    public int Year { get; }

    public string GetErrorMessage() =>
        $"Classic movies must have a release year no later than {Year}.";

    protected override ValidationResult IsValid(object value,
        ValidationContext validationContext)
    {
        var movie = (Movie)validationContext.ObjectInstance;
        var releaseYear = ((DateTime)value).Year;

        if (movie.Genre == Genre.Classic && releaseYear > Year)
        {
            return new ValidationResult(GetErrorMessage());
        }

        return ValidationResult.Success;
    }
}

Proměnná movie v předchozím příkladu představuje Movie objekt, který obsahuje data z odeslání formuláře. Pokud ověření selže, ValidationResult vrátí se chybová zpráva.

IValidatableObject

Předchozí příklad funguje jenom s Movie typy. Další možností ověření na úrovni třídy je implementovat IValidatableObject do třídy modelu, jak je znázorněno v následujícím příkladu:

public class ValidatableMovie : IValidatableObject
{
    private const int _classicYear = 1960;

    public int Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Title { get; set; }

    [DataType(DataType.Date)]
    [Display(Name = "Release Date")]
    public DateTime ReleaseDate { get; set; }

    [Required]
    [StringLength(1000)]
    public string Description { get; set; }

    [Range(0, 999.99)]
    public decimal Price { get; set; }

    public Genre Genre { get; set; }

    public bool Preorder { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (Genre == Genre.Classic && ReleaseDate.Year > _classicYear)
        {
            yield return new ValidationResult(
                $"Classic movies must have a release year no later than {_classicYear}.",
                new[] { nameof(ReleaseDate) });
        }
    }
}

Ověření uzlu nejvyšší úrovně

Mezi uzly nejvyšší úrovně patří:

  • Parametry akce
  • Vlastnosti kontroleru
  • Parametry obslužné rutiny stránky
  • Vlastnosti modelu stránky

Uzly nejvyšší úrovně vázané na model se ověřují kromě ověřování vlastností modelu. V následujícím příkladu ukázkové aplikaceVerifyPhone metoda používá RegularExpressionAttribute k ověření parametru phone akce:

[AcceptVerbs("GET", "POST")]
public IActionResult VerifyPhone(
    [RegularExpression(@"^\d{3}-\d{3}-\d{4}$")] string phone)
{
    if (!ModelState.IsValid)
    {
        return Json($"Phone {phone} has an invalid format. Format: ###-###-####");
    }

    return Json(true);
}

Uzly nejvyšší úrovně můžou používat BindRequiredAttribute s ověřovacími atributy. V následujícím příkladu ukázkové aplikace metoda určuje, CheckAge že age parametr musí být vázán z řetězce dotazu při odeslání formuláře:

[HttpPost]
public IActionResult CheckAge([BindRequired, FromQuery] int age)
{

Na stránce Check Age (CheckAge.cshtml) jsou dva formuláře. První formulář odešle Age hodnotu 99 jako parametr řetězce dotazu: https://localhost:5001/Users/CheckAge?Age=99.

Když se odešle správně formátovaný age parametr z řetězce dotazu, formulář se ověří.

Druhý formulář na stránce Kontrola věku odešle Age hodnotu v textu požadavku a ověření selže. Vazba selže, protože age parametr musí pocházet z řetězce dotazu.

Maximální počet chyb

Ověření se zastaví, když dojde k dosažení maximálního počtu chyb (ve výchozím nastavení 200). Toto číslo můžete nakonfigurovat následujícím kódem:Startup.ConfigureServices

services.AddRazorPages()
    .AddMvcOptions(options =>
    {
        options.MaxModelValidationErrors = 50;
        options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
            _ => "The field is required.");
    });

services.AddSingleton<IValidationAttributeAdapterProvider,
    CustomValidationAttributeAdapterProvider>();

Maximální rekurze

ValidationVisitor prochází graf objektů modelu, který se ověřuje. U modelů, které jsou hluboké nebo jsou nekonečně rekurzivní, může ověření vést k přetečení zásobníku. MvcOptions.MaxValidationDepth poskytuje způsob, jak předčasně zastavit ověření, pokud rekurz návštěvník překročí nakonfigurovanou hloubku. Výchozí hodnota MvcOptions.MaxValidationDepth je 32.

Automatický zkrat

Ověření se automaticky přeruší (přeskočí), pokud graf modelu nevyžaduje ověření. Objekty, které modul runtime přeskočí pro ověřování, zahrnují kolekce primitivních objektů (například byte[], string[], Dictionary<string, string>) a komplexní grafy objektů, které nemají žádné validátory.

Ověření na straně klienta

Ověření na straně klienta brání odeslání, dokud není formulář platný. Tlačítko Odeslat spustí JavaScript, který odešle formulář nebo zobrazí chybové zprávy.

Ověření na straně klienta zabrání zbytečnému zaokrouhlení na server, pokud ve formuláři dochází k chybám vstupu. Následující odkazy na skripty podporují _Layout.cshtml_ValidationScriptsPartial.cshtml ověřování na straně klienta:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.js"></script>

Skript jQuery Unobtrusive Validation je vlastní front-end knihovna Microsoftu, která vychází z oblíbeného modulu plug-in jQuery Validation. Bez funkce jQuery Unobtrusive Authentication byste museli kódovat stejnou logiku ověřování na dvou místech: jednou v atributech ověřování na straně serveru u vlastností modelu a pak znovu ve skriptech na straně klienta. Místo toho pomocné rutiny značek a pomocné rutiny HTML používají ověřovací atributy a metadata typů z vlastností modelu k vykreslení atributů HTML 5 data- pro prvky formuláře, které potřebují ověření. jQuery Unobtrusive Validation parsuje data- atributy a předává logiku jQuery Validation, efektivně "kopírování" logiky ověření na straně serveru klientovi. Chyby ověřování můžete v klientovi zobrazit pomocí pomocných rutin značek, jak je znázorněno tady:

<div class="form-group">
    <label asp-for="Movie.ReleaseDate" class="control-label"></label>
    <input asp-for="Movie.ReleaseDate" class="form-control" />
    <span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
</div>

Předchozí pomocné rutiny značek vykreslují následující kód HTML:

<div class="form-group">
    <label class="control-label" for="Movie_ReleaseDate">Release Date</label>
    <input class="form-control" type="date" data-val="true"
        data-val-required="The Release Date field is required."
        id="Movie_ReleaseDate" name="Movie.ReleaseDate" value="">
    <span class="text-danger field-validation-valid"
        data-valmsg-for="Movie.ReleaseDate" data-valmsg-replace="true"></span>
</div>

Všimněte si, že data- atributy ve výstupu HTML odpovídají ověřovacím atributům Movie.ReleaseDate vlastnosti. Atribut data-val-required obsahuje chybovou zprávu, která se zobrazí, pokud uživatel nezaplní pole data vydání. jQuery Unobtrusive Validation předá tuto hodnotu do metody jQuery Validation required(), která pak zobrazí tuto zprávu v doprovodném <prvku span> .

Ověření datového typu je založeno na typu .NET vlastnosti, pokud není přepsán atributem [DataType]. Prohlížeče mají vlastní výchozí chybové zprávy, ale balíček jQuery Validation Unobtrusive Validation může tyto zprávy přepsat. [DataType] atributy a podtřídy, jako je [EmailAddress], umožňují zadat chybovou zprávu.

Neobtěžující ověření

Informace o nepřerušujícím ověření najdete v tomto GitHub problému.

Přidání ověření do dynamických formulářů

jQuery Unobtrusive Validation předá ověřovací logiku a parametry do jQuery Validation při prvním načtení stránky. Proto ověřování nefunguje automaticky na dynamicky generovaných formulářích. Pokud chcete povolit ověření, řekněte jQuery Unobtrusive Validation, aby se dynamický formulář parsuje hned po jeho vytvoření. Například následující kód nastaví ověření na straně klienta ve formuláři přidaném přes AJAX.

$.get({
    url: "https://url/that/returns/a/form",
    dataType: "html",
    error: function(jqXHR, textStatus, errorThrown) {
        alert(textStatus + ": Couldn't add form. " + errorThrown);
    },
    success: function(newFormHTML) {
        var container = document.getElementById("form-container");
        container.insertAdjacentHTML("beforeend", newFormHTML);
        var forms = container.getElementsByTagName("form");
        var newForm = forms[forms.length - 1];
        $.validator.unobtrusive.parse(newForm);
    }
})

Metoda $.validator.unobtrusive.parse() přijímá pro jeden argument selektor jQuery. Tato metoda říká jQuery Unobtrusive Validation parsovat data- atributy formulářů v rámci tohoto selektoru. Hodnoty těchto atributů se pak předají modulu plug-in jQuery Validation.

Přidání ověření do dynamických ovládacích prvků

Metoda $.validator.unobtrusive.parse() funguje na celém formuláři, ne na jednotlivých dynamicky generovaných ovládacích prvcích, jako je například <input> a <select/>. Pokud chcete formulář znovu probrat, odeberte ověřovací data, která byla přidána při analýze formuláře dříve, jak je znázorněno v následujícím příkladu:

$.get({
    url: "https://url/that/returns/a/control",
    dataType: "html",
    error: function(jqXHR, textStatus, errorThrown) {
        alert(textStatus + ": Couldn't add control. " + errorThrown);
    },
    success: function(newInputHTML) {
        var form = document.getElementById("my-form");
        form.insertAdjacentHTML("beforeend", newInputHTML);
        $(form).removeData("validator")    // Added by jQuery Validation
               .removeData("unobtrusiveValidation");   // Added by jQuery Unobtrusive Validation
        $.validator.unobtrusive.parse(form);
    }
})

Vlastní ověřování na straně klienta

Vlastní ověřování na straně klienta se provádí generováním data- atributů HTML, které pracují s vlastním adaptérem jQuery Validation. Následující ukázkový kód adaptéru byl napsán pro [ClassicMovie][ClassicMovieWithClientValidator] atributy, které byly zavedeny dříve v tomto článku:

$.validator.addMethod('classicmovie', function (value, element, params) {
    var genre = $(params[0]).val(), year = params[1], date = new Date(value);

    // The Classic genre has a value of '0'.
    if (genre && genre.length > 0 && genre[0] === '0') {
        // The release date for a Classic is valid if it's no greater than the given year.
        return date.getUTCFullYear() <= year;
    }

    return true;
});

$.validator.unobtrusive.adapters.add('classicmovie', ['year'], function (options) {
    var element = $(options.form).find('select#Movie_Genre')[0];

    options.rules['classicmovie'] = [element, parseInt(options.params['year'])];
    options.messages['classicmovie'] = options.message;
});

Informace o zápisu adaptérů najdete v dokumentaci k ověřování jQuery.

Použití adaptéru pro dané pole se aktivuje data- atributy, které:

  • Označte pole příznakem jako předmět ověření (data-val="true").
  • Identifikace názvu ověřovacího pravidla a textu chybové zprávy (například data-val-rulename="Error message.").
  • Zadejte všechny další parametry, které validátor potřebuje (například data-val-rulename-param1="value").

Následující příklad ukazuje data- atributy atributu ukázkové aplikaceClassicMovie :

<input class="form-control" type="date"
    data-val="true"
    data-val-classicmovie="Classic movies must have a release year no later than 1960."
    data-val-classicmovie-year="1960"
    data-val-required="The Release Date field is required."
    id="Movie_ReleaseDate" name="Movie.ReleaseDate" value="">

Jak bylo uvedeno výše, pomocné rutiny značek a pomocné rutiny HTML používají k vykreslení data- atributů informace z ověřovacích atributů. Existují dvě možnosti pro psaní kódu, které mají za následek vytvoření vlastních data- atributů HTML:

AtributAdapter pro ověřování na straně klienta

Tato metoda vykreslování data- atributů ve formátu HTML se používá ClassicMovie atributem v ukázkové aplikaci. Pokud chcete přidat ověření klienta pomocí této metody:

  1. Vytvořte třídu adaptéru atributu pro vlastní ověřovací atribut. Odvození třídy z AttributeAdapterBase<TAttribute>. Vytvořte metodu AddValidation , která přidá data- atributy do vykresleného výstupu, jak je znázorněno v tomto příkladu:

    public class ClassicMovieAttributeAdapter : AttributeAdapterBase<ClassicMovieAttribute>
    {
        public ClassicMovieAttributeAdapter(ClassicMovieAttribute attribute,
            IStringLocalizer stringLocalizer)
            : base(attribute, stringLocalizer)
        {
    
        }
    
        public override void AddValidation(ClientModelValidationContext context)
        {
            MergeAttribute(context.Attributes, "data-val", "true");
            MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage(context));
    
            var year = Attribute.Year.ToString(CultureInfo.InvariantCulture);
            MergeAttribute(context.Attributes, "data-val-classicmovie-year", year);
        }
    
        public override string GetErrorMessage(ModelValidationContextBase validationContext) =>
            Attribute.GetErrorMessage();
    }
    
  2. Vytvořte třídu zprostředkovatele adaptéru, která implementuje IValidationAttributeAdapterProvider. GetAttributeAdapter V metodě předejte vlastní atribut konstruktoru adaptéru, jak je znázorněno v tomto příkladu:

    public class CustomValidationAttributeAdapterProvider : IValidationAttributeAdapterProvider
    {
        private readonly IValidationAttributeAdapterProvider baseProvider =
            new ValidationAttributeAdapterProvider();
    
        public IAttributeAdapter GetAttributeAdapter(ValidationAttribute attribute,
            IStringLocalizer stringLocalizer)
        {
            if (attribute is ClassicMovieAttribute classicMovieAttribute)
            {
                return new ClassicMovieAttributeAdapter(classicMovieAttribute, stringLocalizer);
            }
    
            return baseProvider.GetAttributeAdapter(attribute, stringLocalizer);
        }
    }
    
  3. Zaregistrujte poskytovatele adaptéru pro DI v Startup.ConfigureServices:

    services.AddRazorPages()
        .AddMvcOptions(options =>
        {
            options.MaxModelValidationErrors = 50;
            options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
                _ => "The field is required.");
        });
    
    services.AddSingleton<IValidationAttributeAdapterProvider,
        CustomValidationAttributeAdapterProvider>();
    

IClientModelValidator pro ověřování na straně klienta

Tato metoda vykreslování data- atributů ve formátu HTML se používá ClassicMovieWithClientValidator atributem v ukázkové aplikaci. Pokud chcete přidat ověření klienta pomocí této metody:

  • V atributu vlastního ověření implementujte IClientModelValidator rozhraní a vytvořte metodu AddValidation . AddValidation V metodě přidejte data- atributy pro ověření, jak je znázorněno v následujícím příkladu:

    public class ClassicMovieWithClientValidatorAttribute :
        ValidationAttribute, IClientModelValidator
    {
        public ClassicMovieWithClientValidatorAttribute(int year)
        {
            Year = year;
        }
    
        public int Year { get; }
    
        public void AddValidation(ClientModelValidationContext context)
        {
            MergeAttribute(context.Attributes, "data-val", "true");
            MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage());
    
            var year = Year.ToString(CultureInfo.InvariantCulture);
            MergeAttribute(context.Attributes, "data-val-classicmovie-year", year);
        }
    
        public string GetErrorMessage() =>
            $"Classic movies must have a release year no later than {Year}.";
    
        protected override ValidationResult IsValid(object value,
            ValidationContext validationContext)
        {
            var movie = (Movie)validationContext.ObjectInstance;
            var releaseYear = ((DateTime)value).Year;
    
            if (movie.Genre == Genre.Classic && releaseYear > Year)
            {
                return new ValidationResult(GetErrorMessage());
            }
    
            return ValidationResult.Success;
        }
    
        private bool MergeAttribute(IDictionary<string, string> attributes, string key, string value)
        {
            if (attributes.ContainsKey(key))
            {
                return false;
            }
    
            attributes.Add(key, value);
            return true;
        }
    }
    

Zakázání ověřování na straně klienta

Následující kód zakáže ověření klienta na Razor stránkách:

services.AddRazorPages()
    .AddViewOptions(options =>
    {
        options.HtmlHelperOptions.ClientValidationEnabled = false;
    });

Další možnosti zakázání ověřování na straně klienta:

  • Zakomentujte odkaz na _ValidationScriptsPartial všechny .cshtml soubory.
  • Odeberte obsah souboru Pages\Shared_ValidationScriptsPartial.cshtml .

Předchozí přístup nezabrání ověřování na straně klienta ASP.NET Core IdentityRazor knihovně tříd. Další informace najdete v tématu Generování uživatelského rozhraní Identity v projektech ASP.NET Core.

Další materiály