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

Od Kirka Larkin

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

Zobrazit nebo stáhnout vzorový kód (Jak stáhnout).

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 mezi modely , jsou obvykle chyby převodu dat. Například "x" je zadáno v poli typu Integer. K ověření modelu dochází po vazbě modelu a hlášení chyb, kde data neodpovídají obchodním pravidlům. Například hodnota 0 se zadává v poli, které očekává hodnocení mezi 1 a 5.

Vazba modelů i ověřování modelu proběhne před provedením akce kontroleru nebo Razor metody obslužné rutiny stránky. U webových aplikací je zodpovědností aplikace vhodné je kontrolovat ModelState.IsValid a reagovat. 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");
}

Řadiče webového rozhraní API nemusí kontrolovat, ModelState.IsValid jestli mají [ApiController] atribut. V takovém případě je vrácena Automatická odpověď HTTP 400 obsahující podrobnosti o chybě, pokud stav modelu není platný. Další informace najdete v tématu Automatické odpovědi HTTP 400.

Znovu spustit ověření

Ověřování je automatické, ale můžete je chtít opakovat ručně. Můžete například vypočítat hodnotu pro vlastnost a chtít znovu spustit ověřování po nastavení vlastnosti na vypočítanou hodnotu. Chcete-li znovu spustit ověřování, zavolejte ModelStateDictionary.ClearValidationState na Vymazat ověření specifické pro model ověřený za tímto TryValidateModel :

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

Atributy ověřování

Atributy ověřování umožňují zadat pravidla ověřování pro vlastnosti modelu. Následující příklad z ukázkové aplikace zobrazuje třídu modelu s poznámkou ověřování atributů. [ClassicMovie]Atribut je vlastní ověřovací atribut a jsou integrovány ostatní. Není zobrazeno [ClassicMovieWithClientValidator] . [ClassicMovieWithClientValidator] 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é z vestavěných ověřovacích atributů:

  • [ValidateNever]: ValidateNeverAttribute Určuje, že vlastnost nebo parametr by měly být vyloučeny z ověřování.
  • [CreditCard]: Ověří, zda má vlastnost formát kreditní karty. Vyžaduje Další metody ověření jQuery.
  • [Compare]: Ověří, že se dvě vlastnosti v modelu shodují.
  • [EmailAddress]: Ověří, zda má vlastnost formát e-mailu.
  • [Phone]: Ověří, zda má vlastnost formát telefonního čísla.
  • [Range]: Ověří, že hodnota vlastnosti spadá do zadaného rozsahu.
  • [RegularExpression]: Ověří, že hodnota vlastnosti odpovídá zadanému regulárnímu výrazu.
  • [Required]: Ověří, že pole nemá hodnotu null. Podrobnosti o chování tohoto atributu naleznete v [Required] atributu Attribute .
  • [StringLength]: Ověří, že hodnota vlastnosti řetězce nepřekračuje zadané omezení délky.
  • [Url]: Ověří, zda má vlastnost formát adresy URL.
  • [Remote]: Ověří vstup na straně klienta voláním metody Action na serveru. Podrobnosti o chování tohoto atributu naleznete v [Remote] atributu Attribute .

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

Chybové zprávy

Atributy ověřování 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.")]

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

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

Při použití na Name vlastnost bude chybová zpráva vytvořená v předchozím kódu "Délka názvu musí být v rozmezí 6 až 8."

Chcete-li zjistit, které parametry jsou předány String.Format pro konkrétní chybovou zprávu atributu, přečtěte si zdrojový kód pro anotace.

Typy odkazů, které neumožňují hodnotu null a atribut [required]

Systém ověřování zpracovává parametry bez hodnoty null nebo vázané vlastnosti, jako kdyby měl [Required] atribut. Když povolíte Nullable kontexty, MVC implicitně spustí ověřování vlastností, které neumožňují hodnotu null nebo parametry, jako kdyby byly s atributem [Required] . 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í hodnota Name v příspěvku JSON nebo Form způsobí chybu ověřování. Použijte odkazový typ s možnou hodnotou null, aby bylo možné zadat hodnoty null nebo chybějící hodnoty pro Name vlastnost:

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

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

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

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

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

Vazba modelu pro vlastnost, která nemůže mít hodnotu null, může selhat, což vede k chybové zprávě, jako je například The value '' is invalid . Chcete-li zadat vlastní chybovou zprávu pro ověřování na straně serveru pro typy, které neumožňují hodnotu null, máte následující možnosti:

  • Převést pole na hodnotu null (například decimal? místo decimal ). Nullable <T> typy hodnot jsou zpracovány jako 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 vazeb modelů, které lze nastavit jako výchozí zprávy pro, naleznete v tématu DefaultModelBindingMessageProvider .

[Požadováno] ověřování na klientovi

Typy a řetězce, které neumožňují hodnotu null, jsou v porovnání s tímto serverem zpracovávány jinak v klientovi. Na klientovi:

  • Hodnota se považuje za přítomnou pouze v případě, že je pro ni zadán vstup. Proto ověřování na straně klienta zpracovává typy, které neumožňují hodnotu null, stejné jako typy s možnou hodnotou null.
  • Prázdné znaky v poli řetězce se považují za platný vstup metodou jQuery vyžadované ověřením. Ověřování na straně serveru považuje požadované pole řetězce za neplatné, pokud je zadána pouze mezera.

Jak bylo uvedeno dříve, typy neumožňující hodnotu null jsou považovány za, i když mají [Required] atribut. To znamená, že získáte ověřování na straně klienta i v případě, že atribut nepoužijete [Required] . Pokud však atribut nepoužíváte, zobrazí se výchozí chybová zpráva. Chcete-li zadat vlastní chybovou zprávu, použijte atribut.

[Remote] – atribut

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

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

  1. Vytvořte metodu Action pro volání JavaScriptu. Vzdálená metoda ověření jQuery očekává odpověď JSON:

    • true znamená, že jsou vstupní data platná.
    • false, undefined nebo null znamená, že vstup není platný. 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 poznámkujte vlastnost s [Remote] atributem, 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; }
    

    [Remote]Atribut je v Microsoft.AspNetCore.Mvc oboru názvů.

Další pole

AdditionalFieldsVlastnost [Remote] atributu umožňuje ověřit kombinace polí s daty na serveru. Pokud má User model například FirstName a LastName vlastnosti, můžete chtít ověřit, že žádní stávající uživatelé již nemají odpovídající dvojici názvů. 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 lze nastavit explicitně na řetězce "FirstName" a "LastName", ale pomocí operátoru nameof se zjednoduší pozdější refaktoring. Metoda Action pro toto ověření musí přijmout oba firstName argumenty a 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á jméno nebo příjmení, JavaScript vytvoří vzdálené volání, aby viděli, jestli se tento pár názvů povedl.

Chcete-li ověřit dvě nebo více dalších polí, poskytněte je jako seznam oddělený čárkami. Chcete-li 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; }

AdditionalFieldsPodobně jako všechny argumenty atributu musí být konstantní výraz. Proto nepoužívejte interpolované řetězce nebo volání Join k inicializaci AdditionalFields .

Alternativy k předdefinovaným atributům

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

Vlastní atributy

U scénářů, které vestavěné atributy ověřování nezpracovávají, můžete vytvořit vlastní ověřovací atributy. Vytvořte třídu, která dědí z ValidationAttribute , a přepište IsValid metodu.

IsValidMetoda přijímá objekt s názvem hodnota, což je vstup, který má být ověřen. Přetížení také přijímá ValidationContext objekt, který poskytuje další informace, jako je například instance modelu vytvořená vazbou modelu.

Následující příklad ověří, že datum vydání filmu v klasickém žánru nenásleduje po zadaném roce. [ClassicMovie]Atribut:

  • Se spouští 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;
    }
}

movieProměnná v předchozím příkladu představuje Movie objekt, který obsahuje data z odesílání formuláře. Pokud se ověření nepovede, ValidationResult vrátí se chybová zpráva.

IValidatableObject

Předchozí příklad funguje pouze s Movie typy. Další možností pro ověřování na úrovni třídy je implementovat 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; }

    [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ěřování uzlu nejvyšší úrovně

Uzly nejvyšší úrovně zahrnují:

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

Kromě ověřování vlastností modelu jsou ověřovány i uzly nejvyšší úrovně svázané s modelem. V následujícím příkladu z ukázkové aplikace VerifyPhone Metoda používá RegularExpressionAttribute k ověření phone parametru 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ě mohou být použity BindRequiredAttribute s atributy ověřování. V následujícím příkladu z ukázkové aplikace CheckAge určuje metoda, že age parametr musí být svázán z řetězce dotazu při odeslání formuláře:

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

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

Při odeslání správně formátovaného age parametru z řetězce dotazu se formulář ověří.

Druhý formulář na stránce Kontrola stáří odesílá Age hodnotu v těle žádosti a ověření se nepovede. Vazba se nezdařila, protože age parametr musí pocházet z řetězce dotazu.

Maximální počet chyb

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

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

services.AddSingleton<IValidationAttributeAdapterProvider,
    CustomValidationAttributeAdapterProvider>();

Maximální rekurze

ValidationVisitor projde grafem objektu ověřovaného modelu. U modelů, které jsou hluboko nebo jsou nekonečně rekurzivní, může ověřování způsobit přetečení zásobníku. MvcOptions. MaxValidationDepth poskytuje způsob, jak zastavit ověřování v brzkém případě, kdy rekurze návštěvníka překročí nakonfigurovanou hloubku. Výchozí hodnota MvcOptions.MaxValidationDepth je 32.

Automatické krátké okruhy

Ověřování je automaticky zkrácené (vynecháno), pokud model grafu nevyžaduje ověření. Objekty, které modul runtime přeskočí ověřování pro zahrnutí kolekcí primitivních elementů (například byte[] , string[] , Dictionary<string, string> ) a složitých grafů objektů, které nemají žádné validátory.

Zakázat ověřování

Zakázání ověřování:

  1. Vytvořte implementaci IObjectModelValidator , která neoznačí žádná pole jako neplatnou.

    public class NullObjectModelValidator : IObjectModelValidator
    {
        public void Validate(ActionContext actionContext,
            ValidationStateDictionary validationState, string prefix, object model)
        {
    
        }
    }
    
  2. Přidejte následující kód k Startup.ConfigureServices nahrazení výchozí IObjectModelValidator implementace v kontejneru vkládání závislostí.

    services.AddSingleton<IObjectModelValidator, NullObjectModelValidator>();
    

Pořád se můžou zobrazit chyby stavu modelu, které pocházejí z vazby modelu.

Ověřování na straně klienta

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

Ověřování na straně klienta zabrání zbytečnému přenosu na server, pokud dojde k chybám vstupu na formuláři. Následující odkazy skriptu v _Layout. cshtml a _ValidationScriptsPartial. cshtml podporují ověřování na straně klienta:

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

Skript jQuery pro ověření je vlastní knihovna front-end Microsoftu, která se vytváří na oblíbený modul plug-in pro ověření jQuery . Bez nenáročného ověřování by bylo nutné kód stejné ověřovací logiky nakódovat na dvou místech: jednou v atributech ověřování na straně serveru u vlastností modelu a pak znovu v skriptech na straně klienta. Místo toho můžou pomocníky značek a nápovědu HTML používat atributy ověřování a metadata typu z vlastností modelu k vykreslování atributů HTML 5 data- pro prvky formuláře, které vyžadují ověření. jQuery nenáročné ověřování analyzuje data- atributy a předá logiku k ověřování jQuery a efektivně "kopíruje" logiku ověřování na straně serveru klientovi. Chyby ověřování můžete zobrazit na klientovi pomocí značek pomocníka, jak je znázorněno zde:

<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ík značek vykresluje 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í atributům ověřování pro Movie.ReleaseDate vlastnost. data-val-requiredAtribut obsahuje chybovou zprávu, která se zobrazí, pokud uživatel neplní pole Datum vydání. jQuery unpassing předá tuto hodnotu metodě pro ověření jQuery Required () , která pak zobrazí tuto zprávu v doprovodném <span> prvku.

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

Nenáročná ověření

informace o nenáročnosti ověřování najdete v tomto GitHub problému.

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

jQuery – neúspěšné ověření projde logiku ověřování a parametry k ověření jQuery při prvním načtení stránky. Proto ověřování nefunguje automaticky na dynamicky generovaných formulářích. Chcete-li povolit ověřování, řekněte jQuery nenápadu ověřování, aby se dynamický formulář analyzoval ihned po jeho vytvoření. Například následující kód nastaví ověřování na straně klienta na formuláři přidaném prostřednictvím jazyka 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);
    }
})

$.validator.unobtrusive.parse()Metoda přijímá selektor jQuery pro svůj jeden argument. Tato metoda oznamuje nenáročné ověřování, aby bylo možné analyzovat data- atributy formulářů v rámci tohoto selektoru. Hodnoty těchto atributů jsou poté předány modulu plug-in pro ověření jQuery.

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

$.validator.unobtrusive.parse()Metoda funguje na celém formuláři, nikoli na jednotlivých dynamicky generovaných ovládacích prvcích, například <input> a <select/> . Chcete-li znovu analyzovat formulář, odeberte data ověřování, 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é fungují s vlastním ověřovacím adaptérem jQuery. Následující vzorový kód adaptéru byl napsán pro [ClassicMovie] [ClassicMovieWithClientValidator] atributy a, které byly představeny 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 tom, jak psát adaptéry, najdete v dokumentaci k ověření jQuery.

Použití adaptéru pro dané pole se spustí pomocí data- atributů, které:

  • Označte pole jako podléhající ověřování ( data-val="true" ).
  • Identifikujte název ověřovacího pravidla a text chybové zprávy (například data-val-rulename="Error message." ).
  • Zadejte další parametry, které vyžaduje validátor (například data-val-rulename-param1="value" ).

Následující příklad ukazuje data- atributy pro atribut ukázkové aplikace ClassicMovie :

<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 dříve, pomocníkům značek a značkám HTML se při vykreslování atributů používají informace z atributů ověřování data- . Existují dvě možnosti pro psaní kódu, který je výsledkem vytváření vlastních data- atributů HTML:

  • Vytvořte třídu, která je odvozena z AttributeAdapterBase<TAttribute> třídy a třídu, která implementuje IValidationAttributeAdapterProvider , a zaregistrujte svůj atribut a jeho adaptér v di. Tato metoda následuje za instančním objektem zodpovědnosti v tomto ověřovacím kódu souvisejícím se serverem a klientem je v samostatných třídách. Adaptér má také výhodu, že protože je zaregistrován v DI, jsou v případě potřeby k dispozici jiné služby v DI.
  • Implementujte IClientModelValidator ve své ValidationAttribute třídě. Tato metoda může být vhodná, pokud atribut neprovádí žádné ověřování na straně serveru a nepotřebuje žádné služby od DI.

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

Tato metoda vykreslování data- atributů ve formátu HTML je používána ClassicMovie atributem v ukázkové aplikaci. Přidání ověřování klientů pomocí této metody:

  1. Vytvořte třídu adaptéru atributů pro vlastní ověřovací atribut. Odvodit třídu z AttributeAdapterBase<TAttribute> . Vytvořte AddValidation metodu, která přidá data- atributy do vykresleného výstupu, jak je znázorněno v následujícím 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 poskytovatele adaptéru, která implementuje IValidationAttributeAdapterProvider . V GetAttributeAdapter metodě předejte vlastní atribut konstruktoru adaptéru, jak je znázorněno v následujícím 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 je používána ClassicMovieWithClientValidator atributem v ukázkové aplikaci. Přidání ověřování klientů pomocí této metody:

  • Ve vlastním ověřovacím atributu implementujte IClientModelValidator rozhraní a vytvořte AddValidation metodu. V AddValidation 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ázat ověřování na straně klienta

Následující kód zakáže ověřování 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:

  • Odkomentujte odkaz na _ValidationScriptsPartial ve všech souborech . cshtml .
  • Odeberte obsah souboru Pages\Shared _ ValidationScriptsPartial. cshtml .

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

Další zdroje informací

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

Zobrazit nebo stáhnout vzorový kód (Jak stáhnout).

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 mezi modely , jsou obvykle chyby převodu dat (například "x" je zadáno v poli, které očekává celé číslo). K ověření modelu dochází po vazbě modelu a hlášení chyb, kde data neodpovídají obchodním pravidlům (například hodnota 0 je zadána v poli, které očekává hodnocení mezi 1 a 5).

Vazba modelů i ověřování probíhá před provedením akce kontroleru nebo Razor metody obslužné rutiny stránky. U webových aplikací je zodpovědností aplikace vhodné je kontrolovat ModelState.IsValid a reagovat. Webové aplikace obvykle znovu zobrazí stránku s chybovou zprávou:

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

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

    return RedirectToPage("./Index");
}

Řadiče webového rozhraní API nemusí kontrolovat, ModelState.IsValid jestli mají [ApiController] atribut. V takovém případě je vrácena Automatická odpověď HTTP 400 obsahující podrobnosti o chybě, pokud stav modelu není platný. Další informace najdete v tématu Automatické odpovědi HTTP 400.

Znovu spustit ověření

Ověřování je automatické, ale můžete je chtít opakovat ručně. Můžete například vypočítat hodnotu pro vlastnost a chtít znovu spustit ověřování po nastavení vlastnosti na vypočítanou hodnotu. Chcete-li znovu spustit ověřování, zavolejte TryValidateModel metodu, jak je znázorněno zde:

var movie = new Movie
{
    Title = title,
    Genre = genre,
    ReleaseDate = modifiedReleaseDate,
    Description = description,
    Price = price,
    Preorder = preorder,
};

TryValidateModel(movie);

if (ModelState.IsValid)
{
    _context.AddMovie(movie);
    _context.SaveChanges();

    return RedirectToAction(actionName: nameof(Index));
}

return View(movie);

Atributy ověřování

Atributy ověřování umožňují zadat pravidla ověřování pro vlastnosti modelu. Následující příklad z ukázkové aplikace zobrazuje třídu modelu s poznámkou ověřování atributů. [ClassicMovie]Atribut je vlastní ověřovací atribut a jsou integrovány ostatní. Není zobrazeno [ClassicMovie2] , který 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)]
    public DateTime ReleaseDate { get; set; }

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

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

    [Required]
    public Genre Genre { get; set; }

    public bool Preorder { get; set; }
}

Předdefinované atributy

Mezi předdefinované atributy ověřování patří:

  • [CreditCard]: Ověří, zda má vlastnost formát kreditní karty.
  • [Compare]: Ověří, že se dvě vlastnosti v modelu shodují. Například soubor Register. cshtml. cs používá [Compare] k ověření, že se dvě zadaná hesla shodují. Generování Identity uživatelského rozhraní Chcete-li zobrazit kód registrace.
  • [EmailAddress]: Ověří, zda má vlastnost formát e-mailu.
  • [Phone]: Ověří, zda má vlastnost formát telefonního čísla.
  • [Range]: Ověří, že hodnota vlastnosti spadá do zadaného rozsahu.
  • [RegularExpression]: Ověří, že hodnota vlastnosti odpovídá zadanému regulárnímu výrazu.
  • [Required]: Ověří, že pole nemá hodnotu null. Podrobnosti o chování tohoto atributu naleznete v [Required] atributu Attribute .
  • [StringLength]: Ověří, že hodnota vlastnosti řetězce nepřekračuje zadané omezení délky.
  • [Url]: Ověří, zda má vlastnost formát adresy URL.
  • [Remote]: Ověří vstup na straně klienta voláním metody Action na serveru. Podrobnosti o chování tohoto atributu naleznete v [Remote] atributu Attribute .

Při použití [RegularExpression] atributu s ověřováním na straně klienta je regulární výraz spuštěn v jazyce JavaScript na klientovi. To znamená, že se použije chování pro porovnání ECMAScript . další informace najdete v tomto GitHub problému.

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

Chybové zprávy

Atributy ověřování 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.")]

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

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

Při použití na Name vlastnost bude chybová zpráva vytvořená v předchozím kódu "Délka názvu musí být v rozmezí 6 až 8."

Chcete-li zjistit, které parametry jsou předány String.Format pro konkrétní chybovou zprávu atributu, přečtěte si zdrojový kód pro anotace.

[Required] – atribut

Ve výchozím nastavení systém ověřování zpracovává parametry, které neumožňují hodnotu null nebo vlastnosti, jako by měly [Required] atribut. Typy hodnot , jako decimal jsou a, int nejsou null.

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

Na serveru je požadovaná hodnota považována za chybějící, pokud má vlastnost hodnotu null. Pole, které nesmí mít hodnotu null, je vždy platné a chybová zpráva [required] se nezobrazí.

Vazba modelu pro vlastnost, která nemůže mít hodnotu null, může selhat, což vede k chybové zprávě, jako je například The value '' is invalid . Chcete-li zadat vlastní chybovou zprávu pro ověřování na straně serveru pro typy, které neumožňují hodnotu null, máte následující možnosti:

  • Převést pole na hodnotu null (například decimal? místo decimal ). Nullable <T> typy hodnot jsou zpracovány jako 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.AddMvc(options => 
        {
            options.MaxModelValidationErrors = 50;
            options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
                (_) => "The field is required.");
        })
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    services.AddSingleton
        <IValidationAttributeAdapterProvider, 
         CustomValidationAttributeAdapterProvider>();
    

    Další informace o chybách vazeb modelů, které lze nastavit jako výchozí zprávy pro, naleznete v tématu DefaultModelBindingMessageProvider .

[Požadováno] ověřování na klientovi

Typy a řetězce, které neumožňují hodnotu null, jsou v porovnání s tímto serverem zpracovávány jinak v klientovi. Na klientovi:

  • Hodnota se považuje za přítomnou pouze v případě, že je pro ni zadán vstup. Proto ověřování na straně klienta zpracovává typy, které neumožňují hodnotu null, stejné jako typy s možnou hodnotou null.
  • Prázdné znaky v poli řetězce se považují za platný vstup metodou jQuery vyžadované ověřením. Ověřování na straně serveru považuje požadované pole řetězce za neplatné, pokud je zadána pouze mezera.

Jak bylo uvedeno dříve, typy neumožňující hodnotu null jsou považovány za, i když mají [Required] atribut. To znamená, že získáte ověřování na straně klienta i v případě, že atribut nepoužijete [Required] . Pokud však atribut nepoužíváte, zobrazí se výchozí chybová zpráva. Chcete-li zadat vlastní chybovou zprávu, použijte atribut.

[Remote] – atribut

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

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

  1. Vytvořte metodu Action pro volání JavaScriptu. Metoda jQuery Validate Remote očekává odpověď JSON:

    • "true" znamená, že jsou vstupní data platná.
    • "false", undefined nebo null znamená, že vstup není platný. 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 (!_userRepository.VerifyEmail(email))
        {
            return Json($"Email {email} is already in use.");
        }
    
        return Json(true);
    }
    
  2. Ve třídě modelu poznámkujte vlastnost s [Remote] atributem, 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; }
    

    [Remote]Atribut je v Microsoft.AspNetCore.Mvc oboru názvů. pokud nepoužíváte metapackage nebo, nainstalujte balíček Microsoft. AspNetCore. Mvc. ViewFeatures NuGet Microsoft.AspNetCore.App . Microsoft.AspNetCore.All

Další pole

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

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

AdditionalFields lze nastavit explicitně na řetězce "FirstName" a "LastName" , ale použití operátoru nameof zjednodušuje pozdější refaktoring. Metoda Action pro toto ověření musí přijmout argumenty jméno a příjmení:

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

    return Json(true);
}

Když uživatel zadá jméno nebo příjmení, JavaScript vytvoří vzdálené volání, aby viděli, jestli se tento pár názvů povedl.

Chcete-li ověřit dvě nebo více dalších polí, poskytněte je jako seznam oddělený čárkami. Chcete-li 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; }

AdditionalFieldsPodobně jako všechny argumenty atributu musí být konstantní výraz. Proto nepoužívejte interpolované řetězce nebo volání Join k inicializaci AdditionalFields .

Alternativy k předdefinovaným atributům

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

Vlastní atributy

U scénářů, které vestavěné atributy ověřování nezpracovávají, můžete vytvořit vlastní ověřovací atributy. Vytvořte třídu, která dědí z ValidationAttribute , a přepište IsValid metodu.

IsValidMetoda přijímá objekt s názvem hodnota, což je vstup, který má být ověřen. Přetížení také přijímá ValidationContext objekt, který poskytuje další informace, jako je například instance modelu vytvořená vazbou modelu.

Následující příklad ověří, že datum vydání filmu v klasickém žánru nenásleduje po zadaném roce. [ClassicMovie2]Atribut nejprve zkontroluje Žánr a pokračuje pouze v případě, že je klasický. U filmů identifikovaných jako klasických kontroluje datum vydání, aby se zajistilo, že není pozdější než limit předaný konstruktoru atributu.

public class ClassicMovieAttribute : ValidationAttribute
{
    private int _year;

    public ClassicMovieAttribute(int year)
    {
        _year = 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;
    }

    public int Year => _year;

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

movieProměnná v předchozím příkladu představuje Movie objekt, který obsahuje data z odesílání formuláře. IsValidMetoda zkontroluje datum a Žánr. Po úspěšném ověření IsValid vrátí ValidationResult.Success kód. Pokud se ověření nepovede, ValidationResult vrátí se chybová zpráva.

IValidatableObject

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

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

    public int Id { get; set; }

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

    [Required]
    public DateTime ReleaseDate { get; set; }

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

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

    [Required]
    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 earlier than {_classicYear}.",
                new[] { "ReleaseDate" });
        }
    }
}

Ověřování uzlu nejvyšší úrovně

Uzly nejvyšší úrovně zahrnují:

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

Kromě ověřování vlastností modelu jsou ověřovány i uzly nejvyšší úrovně svázané s modelem. V následujícím příkladu z ukázkové aplikace VerifyPhone Metoda používá RegularExpressionAttribute k ověření phone parametru 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ě mohou být použity BindRequiredAttribute s atributy ověřování. V následujícím příkladu z ukázkové aplikace CheckAge určuje metoda, že age parametr musí být svázán z řetězce dotazu při odeslání formuláře:

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

Na stránce pro kontrolu stáří (check. cshtml) Existují dva formuláře. První formulář odešle Age hodnotu 99 jako řetězec dotazu: https://localhost:5001/Users/CheckAge?Age=99 .

Při odeslání správně formátovaného age parametru z řetězce dotazu se formulář ověří.

Druhý formulář na stránce Kontrola stáří odesílá Age hodnotu v těle žádosti a ověření se nepovede. Vazba se nezdařila, protože age parametr musí pocházet z řetězce dotazu.

Při spuštění s CompatibilityVersion.Version_2_1 nebo novějším je ověřování uzlů nejvyšší úrovně ve výchozím nastavení povolené. V opačném případě je ověřování uzlu nejvyšší úrovně zakázané. Výchozí možnost může být přepsána nastavením AllowValidatingTopLevelNodes vlastnosti v ( Startup.ConfigureServices ), jak je znázorněno zde:

services.AddMvc(options => 
    {
        options.MaxModelValidationErrors = 50;
        options.AllowValidatingTopLevelNodes = false;
    })
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

Maximální počet chyb

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

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

Maximální rekurze

ValidationVisitor projde grafem objektu ověřovaného modelu. U modelů, které jsou velmi hlubokoelné nebo nekonečné rekurzivní, může ověřování způsobit přetečení zásobníku. MvcOptions. MaxValidationDepth poskytuje způsob, jak zastavit ověřování v brzkém případě, kdy rekurze návštěvníka překročí nakonfigurovanou hloubku. Výchozí hodnota MvcOptions.MaxValidationDepth je 32 při spuštění v systému CompatibilityVersion.Version_2_2 nebo novějším. Pro starší verze je hodnota null, což znamená bez omezení hloubky.

Automatické krátké okruhy

Ověřování je automaticky zkrácené (vynecháno), pokud model grafu nevyžaduje ověření. Objekty, které modul runtime přeskočí ověřování pro zahrnutí kolekcí primitivních elementů (například byte[] , string[] , Dictionary<string, string> ) a složitých grafů objektů, které nemají žádné validátory.

Zakázat ověřování

Zakázání ověřování:

  1. Vytvořte implementaci IObjectModelValidator , která neoznačí žádná pole jako neplatnou.

    public class NullObjectModelValidator : IObjectModelValidator
    {
        public void Validate(
            ActionContext actionContext,
            ValidationStateDictionary validationState,
            string prefix,
            object model)
        {
        }
    }
    
  2. Přidejte následující kód k Startup.ConfigureServices nahrazení výchozí IObjectModelValidator implementace v kontejneru vkládání závislostí.

    // There is only one `IObjectModelValidator` object,
    // so AddSingleton replaces the default one.
    services.AddSingleton<IObjectModelValidator>(new NullObjectModelValidator());
    

Pořád se můžou zobrazit chyby stavu modelu, které pocházejí z vazby modelu.

Ověřování na straně klienta

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

Ověřování na straně klienta zabrání zbytečnému přenosu na server, pokud dojde k chybám vstupu na formuláři. Následující odkazy skriptu v _Layout. cshtml a _ValidationScriptsPartial. cshtml podporují ověřování na straně klienta:

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

Skript jQuery nenáročného ověřování je vlastní knihovna front-end Microsoftu, která se vytváří na oblíbený modul plug-in jQuery pro ověření . Bez nenáročného ověřování by bylo nutné kód stejné ověřovací logiky nakódovat na dvou místech: jednou v atributech ověřování na straně serveru u vlastností modelu a pak znovu v skriptech na straně klienta. Místo toho můžou pomocníky značek a nápovědu HTML používat atributy ověřování a metadata typu z vlastností modelu k vykreslování atributů HTML 5 data- pro prvky formuláře, které vyžadují ověření. jQuery nenáročné ověřování analyzuje data- atributy a předá logiku do příkazu jQuery Validate a efektivně kopíruje logiku ověřování na straně serveru do klienta. Chyby ověřování můžete zobrazit na klientovi pomocí značek pomocníka, jak je znázorněno zde:

<div class="form-group">
    <label asp-for="ReleaseDate" class="col-md-2 control-label"></label>
    <div class="col-md-10">
        <input asp-for="ReleaseDate" class="form-control" />
        <span asp-validation-for="ReleaseDate" class="text-danger"></span>
    </div>
</div>

Předchozí pomocník značek vykresluje následující kód HTML.

<form action="/Movies/Create" method="post">
    <div class="form-horizontal">
        <h4>Movie</h4>
        <div class="text-danger"></div>
        <div class="form-group">
            <label class="col-md-2 control-label" for="ReleaseDate">ReleaseDate</label>
            <div class="col-md-10">
                <input class="form-control" type="datetime"
                data-val="true" data-val-required="The ReleaseDate field is required."
                id="ReleaseDate" name="ReleaseDate" value="">
                <span class="text-danger field-validation-valid"
                data-valmsg-for="ReleaseDate" data-valmsg-replace="true"></span>
            </div>
        </div>
    </div>
</form>

Všimněte si, že data- atributy ve výstupu HTML odpovídají atributům ověřování pro ReleaseDate vlastnost. data-val-requiredAtribut obsahuje chybovou zprávu, která se zobrazí, pokud uživatel neplní pole Datum vydání. jQuery unpassing předá tuto hodnotu metodě jQuery Required () , která pak zobrazí tuto zprávu v doprovodném <span> prvku.

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

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

jQuery – neúspěšné ověření projde logiku ověření a parametry, které se při prvním načtení stránky ověřují. Proto ověřování nefunguje automaticky na dynamicky generovaných formulářích. Chcete-li povolit ověřování, řekněte jQuery nenápadu ověřování, aby se dynamický formulář analyzoval ihned po jeho vytvoření. Například následující kód nastaví ověřování na straně klienta na formuláři přidaném prostřednictvím jazyka 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);
    }
})

$.validator.unobtrusive.parse()Metoda přijímá selektor jQuery pro svůj jeden argument. Tato metoda oznamuje nenáročné ověřování, aby bylo možné analyzovat data- atributy formulářů v rámci tohoto selektoru. Hodnoty těchto atributů jsou poté předány modulu plug-in jQuery Validate.

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

$.validator.unobtrusive.parse()Metoda funguje na celém formuláři, nikoli na jednotlivých dynamicky generovaných ovládacích prvcích, například <input> a <select/> . Chcete-li znovu analyzovat formulář, odeberte data ověřování, 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 Validate
               .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é fungují s vlastním ověřovacím adaptérem jQuery. Následující vzorový kód adaptéru byl napsán pro ClassicMovie ClassicMovie2 atributy a, které byly představeny dříve v tomto článku:

$.validator.addMethod('classicmovie',
    function (value, element, params) {
        // Get element value. Classic genre has value '0'.
        var genre = $(params[0]).val(),
            year = params[1],
            date = new Date(value);
        if (genre && genre.length > 0 && genre[0] === '0') {
            // Since this is a classic movie, invalid if release date is after given year.
            return date.getUTCFullYear() <= year;
        }

        return true;
    });

$.validator.unobtrusive.adapters.add('classicmovie',
    ['year'],
    function (options) {
        var element = $(options.form).find('select#Genre')[0];
        options.rules['classicmovie'] = [element, parseInt(options.params['year'])];
        options.messages['classicmovie'] = options.message;
    });

Informace o tom, jak psát adaptéry, najdete v dokumentaci ke službě jQuery Validate.

Použití adaptéru pro dané pole se spustí pomocí data- atributů, které:

  • Označte pole jako podléhající ověřování ( data-val="true" ).
  • Identifikujte název ověřovacího pravidla a text chybové zprávy (například data-val-rulename="Error message." ).
  • Zadejte další parametry, které vyžaduje validátor (například data-val-rulename-parm1="value" ).

Následující příklad ukazuje data- atributy pro atribut ukázkové aplikace ClassicMovie :

<input class="form-control" type="datetime"
    data-val="true"
    data-val-classicmovie1="Classic movies must have a release year earlier than 1960."
    data-val-classicmovie1-year="1960"
    data-val-required="The ReleaseDate field is required."
    id="ReleaseDate" name="ReleaseDate" value="">

Jak bylo uvedeno dříve, pomocníkům značek a značkám HTML se při vykreslování atributů používají informace z atributů ověřování data- . Existují dvě možnosti pro psaní kódu, který je výsledkem vytváření vlastních data- atributů HTML:

  • Vytvořte třídu, která je odvozena z AttributeAdapterBase<TAttribute> třídy a třídu, která implementuje IValidationAttributeAdapterProvider , a zaregistrujte svůj atribut a jeho adaptér v di. Tato metoda následuje za instančním objektem zodpovědnosti v tomto ověřovacím kódu souvisejícím se serverem a klientem je v samostatných třídách. Adaptér má také výhodu, že protože je zaregistrován v DI, jsou v případě potřeby k dispozici jiné služby v DI.
  • Implementujte IClientModelValidator ve své ValidationAttribute třídě. Tato metoda může být vhodná, pokud atribut neprovádí žádné ověřování na straně serveru a nepotřebuje žádné služby od DI.

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

Tato metoda vykreslování data- atributů ve formátu HTML je používána ClassicMovie atributem v ukázkové aplikaci. Přidání ověřování klientů pomocí této metody:

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

    public class ClassicMovieAttributeAdapter : AttributeAdapterBase<ClassicMovieAttribute>
    {
        private int _year;
    
        public ClassicMovieAttributeAdapter(ClassicMovieAttribute attribute, IStringLocalizer stringLocalizer) : base (attribute, stringLocalizer)
        {
            _year = attribute.Year;
        }
        public override void AddValidation(ClientModelValidationContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(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)
        {
            return Attribute.GetErrorMessage();
        }
    }
    
  2. Vytvořte třídu poskytovatele adaptéru, která implementuje IValidationAttributeAdapterProvider . V GetAttributeAdapter metodě předejte vlastní atribut konstruktoru adaptéru, jak je znázorněno v následujícím příkladu:

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

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

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

Tato metoda vykreslování data- atributů ve formátu HTML je používána ClassicMovie2 atributem v ukázkové aplikaci. Přidání ověřování klientů pomocí této metody:

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

    
    public class ClassicMovie2Attribute : ValidationAttribute, IClientModelValidator
    {
        private int _year;
    
        public ClassicMovie2Attribute(int year)
        {
            _year = 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;
        }
    
        public void AddValidation(ClientModelValidationContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(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);
        }
        private bool MergeAttribute(IDictionary<string, string> attributes, string key, string value)
        {
            if (attributes.ContainsKey(key))
            {
                return false;
            }
    
            attributes.Add(key, value);
            return true;
        }
        protected string GetErrorMessage()
        {
            return $"Classic movies must have a release year no later than {_year} [from attribute 2].";
        }
    }
    

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

Následující kód zakáže ověřování klienta v zobrazeních MVC:

services.AddMvc().AddViewOptions(options =>
{
    if (_env.IsDevelopment())
    {
        options.HtmlHelperOptions.ClientValidationEnabled = false;
    }
});

A na Razor stránkách:

services.Configure<HtmlHelperOptions>(o => o.ClientValidationEnabled = false);

Další možností pro zakázání ověřování klienta je přidat komentář k odkazu do _ValidationScriptsPartial souboru . cshtml .

Další zdroje informací