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. Napří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. Napří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(AllowEmptyStrings = true)] 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(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í 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(AllowEmptyStrings = true)] atribut. To znamená, že získáte ověřování na straně klienta i v případě, že atribut nepoužijete [Required(AllowEmptyStrings = true)] . 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.

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 atribut , jak je [Remote] 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í k Join inicializaci AdditionalFields .

Alternativy k integrovaným atributům

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

Vlastní atributy

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

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

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

  • Nástroj se spustí 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 se ověření nezdaří, ValidationResult vrátí se chybová zpráva s chybou .

IValidatableObject

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

Kromě ověřování vlastností modelu se ověřují také uzly nejvyšší úrovně vázané na model. V následujícím příkladu z ukázkové aplikace používá metoda k VerifyPhone RegularExpressionAttribute ověření phone parametru akce metodu :

[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ě lze použít s BindRequiredAttribute atributy ověřování. V následujícím příkladu z ukázkové aplikace metoda určuje, že parametr musí být při odeslaném formuláři svázán z CheckAge age řetězce dotazu:

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

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

Při odeslaném správně naformátovaném parametru z řetězce age dotazu se formulář ověří.

Druhý formulář na stránce Check Age (Věk kontroly) odešle hodnotu v textu požadavku a Age ověření se nezdaří. Vazba selže, protože age parametr musí pocovat 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í je to 200). Toto číslo můžete nakonfigurovat pomocí následujícího kódu v Startup.ConfigureServices souboru :

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

services.AddSingleton<IValidationAttributeAdapterProvider,
    CustomValidationAttributeAdapterProvider>();

Maximální rekurze

ValidationVisitor protíná graf objektů ověřovaných modelů. U modelů, které jsou hluboké nebo nekonečně rekurzivní, může ověření vést k přetečení zásobníku. MvcOptions.MaxValidationDepth nabízí způsob, jak v rané fázi zastavit ověřování, pokud rekurze návštěvníka překročí nakonfigurovanou hloubku. Výchozí hodnota je MvcOptions.MaxValidationDepth 32.

Automatický krátký okruh

Ověření se automaticky zkrátí (přeskočí) v případě, že graf modelu nevyžaduje ověření. Mezi objekty, které modul runtime přeskočí ověřování, patří kolekce primitiv (například , , ) a komplexní grafy objektů, které nemají byte[] string[] žádné Dictionary<string, string> validátory.

Ověřování na straně klienta

Ověření na straně klienta zabrání odeslání, dokud formulář nebude 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 zpátečnímu dokončování na server, když ve formuláři dojde k chybám vstupu. Následující skript odkazuje na soubory _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 Unobtrusive Validation je vlastní front-end knihovna Microsoftu, která vychází z oblíbeného modulu plug-in jQuery Validation. Bez nerušiváho ověřování jQuery byste měli stejnou logiku ověřování kódovat 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íci značek a pomocníci HTML používají atributy ověřování a metadata typů z vlastností modelu k vykreslení atributů HTML 5 pro prvky formuláře, data- které potřebují ověření. jQuery Unobtrusive Validation parsuje atributy a předá logiku do ověření jQuery, které efektivně "kopíruje" logiku ověřování na straně data- serveru do klienta. Chyby ověřování můžete v klientovi zobrazit pomocí pomocníků 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á slova 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 data- si, že atributy ve výstupu HTML odpovídají atributům ověřování pro Movie.ReleaseDate vlastnost . Atribut data-val-required obsahuje chybovou zprávu, která se zobrazí, pokud uživatel nevyplní pole data vydání. jQuery Unobtrusive Validation předá tuto hodnotu metodě jQuery Validation required(), která pak tuto zprávu zobrazí v doprovodném <span> elementu.

Ověření datového typu je založené na typu .NET vlastnosti, pokud není přepsáno [DataType] atributem. 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, například [EmailAddress] umožňují zadat chybovou zprávu.

Nerušivá ověřování

Informace o nerušitivním ověřování najdete v tomto GitHub problému.

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

Nerušivá ověření jQuery předá logiku ověřování a parametry do ověření jQuery při prvním načtení stránky. Proto ověřování nefunguje automaticky na dynamicky generovaných formulářích. Pokud chcete povolit ověřování, informujte jQuery Unobtrusive Validation, aby okamžitě po vytvoření parsuje dynamický formulář. Například následující kód nastaví ověřování na straně klienta ve 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);
    }
})

Metoda $.validator.unobtrusive.parse() jako jeden argument přijímá selektor jQuery. Tato metoda říká nerušivavému ověřování jQuery, aby parsuje data- atributy formulářů v tomto selektoru. Hodnoty těchto atributů se pak předá modulu plug-in jQuery Validation.

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

Metoda funguje na celém formuláři, nikoli na $.validator.unobtrusive.parse() jednotlivých dynamicky generovaných ovládacích prvcích, jako jsou <input> a <select/> . Pokud chcete formulář znovu analyzovat, odeberte ověřovací data, která byla přidána při předchozí analýze formuláře, 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 adaptérem jQuery Validation. Následující vzorový kód adaptéru byl napsán pro atributy a , které [ClassicMovie] [ClassicMovieWithClientValidator] jsme představili 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 zapisovat adaptéry, najdete v dokumentaci k ověřování jQuery.

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

  • Označit pole příznakem, že podléhá ověření ( data-val="true" ).
  • Identifikujte název pravidla ověřování 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é ClassicMovie aplikace:

<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 uvedli dříve, pomocníci značek a pomocníci HTML používají informace z atributů ověřování k vykreslení data- atributů. Existují dvě možnosti psaní kódu, které mají za výsledek vytvoření vlastních data- atributů HTML:

  • Vytvořte třídu odvozenou z třídy a , která implementuje , a zaregistrujte atribut a AttributeAdapterBase<TAttribute> IValidationAttributeAdapterProvider jeho adaptér v individui. Tato metoda se řídí jediným objektem zabezpečení odpovědnosti v ověřovacím kódu souvisejícím se serverem a klientem v samostatných třídách. Adaptér má také tu výhodu, že vzhledem k tomu, že je zaregistrovaný v IN, jsou pro něj v případě potřeby k dispozici další služby v induividui.
  • Implementujte IClientModelValidator ve své ValidationAttribute třídě . Tato metoda může být vhodná, pokud atribut nemá žádné ověřování na straně serveru a nepotřebuje žádné služby od DI.

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

Tuto metodu vykreslování data- atributů v HTML používá atribut v ukázkové ClassicMovie aplikaci. Pokud chcete přidat ověření klienta pomocí této metody:

  1. Vytvořte třídu adaptéru atributů pro vlastní atribut ověření. Odvození třídy z AttributeAdapterBase<TAttribute> . Vytvořte AddValidation metodu, která data- přidá atributy do vykreslené 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 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. Napří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. Napří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(AllowEmptyStrings = true)] 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(AllowEmptyStrings = true)] atribut. To znamená, že získáte ověřování na straně klienta i v případě, že atribut nepoužijete [Required(AllowEmptyStrings = true)] . 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 opište vlastnost atributem, který odkazuje na metodu ověřovací akce, jak je znázorněno [Remote] v následujícím příkladu:

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

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

Další pole

Vlastnost AdditionalFields atributu [Remote] umožňuje ověřit kombinace polí s daty na serveru. Pokud má například model vlastnosti a , můžete chtít ověřit, že žádní stávající uživatelé už nemají tento User FirstName pár LastName 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 explicitně nastavit na řetězce a , ale použití "FirstName" "LastName" operátoru nameof zjednodušuje pozdější refaktoring. Metoda akce pro toto ověření musí přijímat 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 provede vzdálené volání, aby viděl, jestli byla tato dvojice jmen pořízena.

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 atribut , jak je [Remote] 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í k Join inicializaci AdditionalFields .

Alternativy k integrovaným atributům

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

Vlastní atributy

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

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

Následující příklad ověří, že datum vydání filmu v klasickém žánru není pozdější než zadaný rok. Atribut [ClassicMovie2] nejprve zkontroluje žánr a pokračuje pouze v případě, že jde o klasický . U filmů identifikovaných jako klasické kontroluje datum vydání, aby se ujistil, ž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}.";
    }
}

Proměnná movie v předchozím příkladu představuje Movie objekt, který obsahuje data z odeslání formuláře. Metoda IsValid zkontroluje datum a žánr. Po úspěšném ověření IsValid vrátí ValidationResult.Success kód. Pokud se ověření nezdaří, ValidationResult vrátí se chybová zpráva s chybou .

IValidatableObject

Předchozí příklad funguje pouze s Movie typy. Další možností ověřování na úrovni třídy je implementace ve třídě IValidatableObject 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ěření uzlu nejvyšší úrovně

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

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

Kromě ověřování vlastností modelu se ověřují také uzly nejvyšší úrovně vázané na model. V následujícím příkladu z ukázkové aplikace používá metoda k VerifyPhone RegularExpressionAttribute ověření phone parametru akce metodu :

[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ě lze použít s BindRequiredAttribute atributy ověřování. V následujícím příkladu z ukázkové aplikace metoda určuje, že parametr musí být při odeslaném formuláři svázán z CheckAge age řetězce dotazu:

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

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

Při odeslaném správně naformátovaném parametru z řetězce age dotazu se formulář ověří.

Druhý formulář na stránce Check Age (Stáří kontroly) odešle hodnotu v textu požadavku a Age ověření se nezdaří. Vazba selže, protože age parametr musí pocovat z řetězce dotazu.

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

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

Maximální počet chyb

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

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 protíná graf objektů ověřovaných modelů. U velmi hlubokých nebo nekonečně rekurzivních modelů může ověření vést k přetečení zásobníku. MvcOptions.MaxValidationDepth nabízí způsob, jak v rané fázi zastavit ověřování, pokud rekurze návštěvníka překročí nakonfigurovanou hloubku. Výchozí hodnota je MvcOptions.MaxValidationDepth 32 při spuštění s CompatibilityVersion.Version_2_2 nebo novějším. Pro starší verze má hodnota hodnotu null, což znamená žádné omezení hloubky.

Automatický krátký okruh

Ověření se automaticky zkrátí (přeskočí) v případě, že graf modelu nevyžaduje ověření. Mezi objekty, které modul runtime přeskočí ověřování, patří kolekce primitiv (například , , ) a komplexní grafy objektů, které nemají byte[] string[] žádné Dictionary<string, string> validátory.

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

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

  1. Vytvořte implementaci , IObjectModelValidator která nebude označovat žádná pole jako neplatná.

    public class NullObjectModelValidator : IObjectModelValidator
    {
        public void Validate(
            ActionContext actionContext,
            ValidationStateDictionary validationState,
            string prefix,
            object model)
        {
        }
    }
    
  2. Do souboru přidejte následující Startup.ConfigureServices kód, který nahradí výchozí IObjectModelValidator implementaci v kontejneru injektáže závislostí.

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

Stále se můžou zobrazit chyby stavu modelu, které pocházejí z vazby modelu.

Ověřování na straně klienta

Ověření na straně klienta zabrání odeslání, dokud formulář nebude 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 zpátečnímu dokončování na server, když ve formuláři dojde k chybám vstupu. Následující skript odkazuje na soubory _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 Unobtrusive Validation je vlastní front-end knihovna Microsoftu, která vychází z oblíbeného modulu plug-in jQuery Validate. Bez nerušiváho ověřování jQuery byste měli stejnou logiku ověřování kódovat 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íci značek a pomocníci HTML používají atributy ověřování a metadata typů z vlastností modelu k vykreslení atributů HTML 5 pro prvky formuláře, data- které potřebují ověření. jQuery Unobtrusive Validation parsuje atributy a předá logiku do jQuery Validate a efektivně do klienta "zkopíruje" logiku ověřování na straně data- serveru. Chyby ověřování můžete v klientovi zobrazit pomocí pomocníků značek, jak je znázorněno tady:

<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á zařízení značek vykreslují 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 data- si, že atributy ve výstupu HTML odpovídají atributům ověřování pro ReleaseDate vlastnost . Atribut data-val-required obsahuje chybovou zprávu, která se zobrazí, pokud uživatel nevyplní pole data vydání. jQuery Unobtrusive Validation předá tuto hodnotu metodě jQuery Validate required(), která pak tuto zprávu zobrazí v doprovodném <span> elementu.

Ověření datového typu je založené na typu .NET vlastnosti, pokud není přepsáno [DataType] atributem. 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, například [EmailAddress] umožňují zadat chybovou zprávu.

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

Nerušivá ověření jQuery předá logiku ověřování a parametry do jQuery Validate při prvním načtení stránky. Proto ověřování nefunguje automaticky na dynamicky generovaných formulářích. Pokud chcete povolit ověřování, informujte jQuery Unobtrusive Validation, aby dynamickou formu parsuje okamžitě po jeho vytvoření. Například následující kód nastaví ověřování na straně klienta ve 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);
    }
})

Metoda $.validator.unobtrusive.parse() jako jeden argument přijímá selektor jQuery. Tato metoda říká nerušivavému ověřování jQuery, aby parsuje data- atributy formulářů v tomto selektoru. Hodnoty těchto atributů se pak předá modulu plug-in jQuery Validate.

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

Metoda funguje na celém formuláři, nikoli na $.validator.unobtrusive.parse() jednotlivých dynamicky generovaných ovládacích prvcích, jako jsou <input> a <select/> . Pokud chcete formulář znovu analyzovat, odeberte ověřovací data, která byla přidána při předchozí analýze formuláře, 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ěření na straně klienta se provádí generováním atributů HTML, které fungují s vlastním adaptérem data- jQuery Validate. Následující vzorový kód adaptéru byl napsán pro atributy a , které ClassicMovie ClassicMovie2 jsme představili 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 zapisovat adaptéry, najdete v dokumentaci k jQuery Validate.

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

  • Označí pole příznakem, že podléhá ověření ( data-val="true" ).
  • Identifikujte název pravidla ověřování a text chybové zprávy (například data-val-rulename="Error message." ).
  • Zadejte další parametry, které validátor potřebuje (například data-val-rulename-parm1="value" ).

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

<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 jsme uvedli dříve, pomocníci značek a pomocníci HTML používají informace z atributů ověřování k vykreslení data- atributů. Existují dvě možnosti psaní kódu, které mají za výsledek vytvoření vlastních data- atributů HTML:

  • Vytvořte třídu odvozenou z třídy a , která implementuje , a zaregistrujte atribut a AttributeAdapterBase<TAttribute> IValidationAttributeAdapterProvider jeho adaptér do inistrukcí. Tato metoda se řídí jediným objektem zabezpečení odpovědnosti v ověřovacím kódu souvisejícím se serverem a klientem v samostatných třídách. Adaptér má také tu výhodu, že vzhledem k tomu, že je zaregistrovaný v IN, jsou pro něj v případě potřeby k dispozici další služby v induividui.
  • Implementujte IClientModelValidator ve své ValidationAttribute třídě . Tato metoda může být vhodná, pokud atribut nemá žádné ověřování na straně serveru a nepotřebuje žádné služby od diody.

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

Tuto metodu vykreslování data- atributů v HTML používá atribut v ukázkové ClassicMovie aplikaci. Pokud chcete přidat ověření klienta pomocí této metody:

  1. Vytvořte třídu adaptéru atributů pro vlastní atribut ověřování. Odvození třídy z AttributeAdapterBase<TAttribute> . Vytvořte AddValidation metodu, která data- přidá atributy do vykreslené výstupu, jak je znázorněno v tomto 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 metodě předejte konstruktoru adaptéru vlastní atribut , jak GetAttributeAdapter je znázorněno v tomto 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 instrukce 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

Tuto metodu vykreslování data- atributů v HTML používá atribut v ukázkové ClassicMovie2 aplikaci. Pokud chcete přidat ověření klienta pomocí této metody:

  • Ve vlastním atributu ověřování 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ázání ověřování na straně klienta

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

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

A ve Razor stránkách:

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

Další možností zakázání ověření klienta je okomentování odkazu na v _ValidationScriptsPartial souboru .cshtml.

Další zdroje informací