Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
In dit artikel wordt uitgelegd hoe u gebruikersinvoer kunt valideren in een ASP.NET Core MVC- of Razor Pages-app.
Voorbeeldcode bekijken of downloaden (hoe u kunt downloaden).
Model state
De modelstatus vertegenwoordigt fouten die afkomstig zijn van twee subsystemen: modelbinding en modelvalidatie. Fouten die afkomstig zijn van modelbinding zijn over het algemeen fouten bij het converteren van gegevens. Een 'x' wordt bijvoorbeeld ingevoerd in een geheel getalveld. Modelvalidatie vindt plaats na modelbinding en rapporteert fouten waarbij gegevens niet voldoen aan bedrijfsregels. Een 0 wordt bijvoorbeeld ingevoerd in een veld waarin een classificatie tussen 1 en 5 wordt verwacht.
Zowel modelbinding als modelvalidatie vinden plaats vóór de uitvoering van een controlleractie of een Razor Pagina-handlermethode. Voor web-apps is het de verantwoordelijkheid van de app om op de juiste wijze te controleren ModelState.IsValid
en erop te reageren. Web-apps worden de pagina meestal opnieuw weergegeven met een foutbericht, zoals wordt weergegeven in het volgende Razor paginavoorbeeld:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movies.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
Voor ASP.NET Core MVC met controllers en weergaven ziet u in het volgende voorbeeld hoe u binnen een controlleractie kunt controleren ModelState.IsValid
:
public async Task<IActionResult> Create(Movie movie)
{
if (!ModelState.IsValid)
{
return View(movie);
}
_context.Movies.Add(movie);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
Web-API-controllers hoeven niet te controleren ModelState.IsValid
of ze het kenmerk [ApiController] hebben. In dat geval wordt een automatisch HTTP 400-antwoord met foutdetails geretourneerd wanneer de modelstatus ongeldig is. Zie Automatische HTTP 400-antwoordenvoor meer informatie.
Rerun validation
Validatie is automatisch, maar u wilt deze mogelijk handmatig herhalen. U kunt bijvoorbeeld een waarde voor een eigenschap berekenen en de validatie opnieuw uitvoeren nadat u de eigenschap hebt ingesteld op de berekende waarde. Als u de validatie opnieuw wilt uitvoeren, roept ModelStateDictionary.ClearValidationState u aan om de validatie te wissen die specifiek is voor het model dat wordt gevalideerd, gevolgd door 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");
}
Validation attributes
Met validatiekenmerken kunt u validatieregels opgeven voor modeleigenschappen. In het volgende voorbeeld uit de voorbeeld-app ziet u een modelklasse die is geannoteerd met validatiekenmerken. Het [ClassicMovie]
kenmerk is een aangepast validatiekenmerk en de andere kenmerken zijn ingebouwd. Niet weergegeven is [ClassicMovieWithClientValidator]
, wat een alternatieve manier toont om een aangepast kenmerk te implementeren.
public class Movie
{
public int Id { get; set; }
[Required]
[StringLength(100)]
public string Title { get; set; } = null!;
[ClassicMovie(1960)]
[DataType(DataType.Date)]
[Display(Name = "Release Date")]
public DateTime ReleaseDate { get; set; }
[Required]
[StringLength(1000)]
public string Description { get; set; } = null!;
[Range(0, 999.99)]
public decimal Price { get; set; }
public Genre Genre { get; set; }
public bool Preorder { get; set; }
}
Built-in attributes
Hier volgen enkele ingebouwde validatiekenmerken:
- [ValidateNever]: geeft aan dat een eigenschap of parameter moet worden uitgesloten van validatie.
- [CreditCard]: valideert of de eigenschap een creditcardindeling heeft. Hiervoor zijn aanvullende methoden voor jQuery-validatie vereist.
- [Vergelijken]: valideert dat twee eigenschappen in een model overeenkomen.
- [EmailAddress]: valideert of de eigenschap een e-mailindeling heeft.
- [Telefoon]: controleert of de eigenschap een telefoonnummernotatie heeft.
- [Bereik]: valideert of de eigenschapswaarde binnen een opgegeven bereik valt.
- [RegularExpression]: valideert of de eigenschapswaarde overeenkomt met een opgegeven reguliere expressie.
-
[Vereist]: valideert dat het veld niet null is. Zie
[Required]
het kenmerk voor meer informatie over het gedrag van dit kenmerk. - [StringLength]: hiermee wordt gevalideerd dat een waarde van een tekenreekseigenschap geen opgegeven lengtelimiet overschrijdt.
- [Url]: valideert of de eigenschap een URL-indeling heeft.
-
[Extern]: valideert invoer op de client door een actiemethode op de server aan te roepen. Zie
[Remote]
het kenmerk voor meer informatie over het gedrag van dit kenmerk.
Een volledige lijst met validatiekenmerken vindt u in de System.ComponentModel.DataAnnotations naamruimte.
Error messages
Met validatiekenmerken kunt u het foutbericht opgeven dat moet worden weergegeven voor ongeldige invoer. For example:
[StringLength(8, ErrorMessage = "Name length can't be more than 8.")]
Intern worden de kenmerken aangeroepen String.Format met een tijdelijke aanduiding voor de veldnaam en soms aanvullende tijdelijke aanduidingen. For example:
[StringLength(8, ErrorMessage = "{0} length must be between {2} and {1}.", MinimumLength = 6)]
Wanneer het wordt toegepast op een Name
eigenschap, is het foutbericht dat door de voorgaande code is gemaakt, de naamlengte moet tussen 6 en 8 zijn.
Als u wilt zien aan welke parameters worden doorgegeven String.Format
voor het foutbericht van een bepaald kenmerk, raadpleegt u de broncode van DataAnnotations.
JSON-eigenschapsnamen gebruiken in validatiefouten
Wanneer er een validatiefout optreedt, produceert modelvalidatie standaard een ModelStateDictionary met de eigenschapsnaam als foutsleutel. Sommige apps, zoals apps met één pagina, profiteren van het gebruik van JSON-eigenschapsnamen voor validatiefouten die zijn gegenereerd op basis van web-API's. Met de volgende code wordt validatie geconfigureerd voor het gebruik van de SystemTextJsonValidationMetadataProvider
voor het gebruik van JSON-eigenschapsnamen:
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(options =>
{
options.ModelMetadataDetailsProviders.Add(new SystemTextJsonValidationMetadataProvider());
});
var app = builder.Build();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Met de volgende code wordt validatie geconfigureerd om de NewtonsoftJsonValidationMetadataProvider
te gebruiken als JSON-eigenschapsnaam bij gebruik van Json.NET.
using Microsoft.AspNetCore.Mvc.NewtonsoftJson;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(options =>
{
options.ModelMetadataDetailsProviders.Add(new NewtonsoftJsonValidationMetadataProvider());
}).AddNewtonsoftJson();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Zie op GitHub voor een voorbeeld van het beleid voor het gebruik van camel-casingProgram.cs
.
Niet-nullable verwijzingstypen en kenmerk [Vereist]
Het validatiesysteem behandelt niet-nullable parameters of afhankelijke eigenschappen alsof ze een [Required(AllowEmptyStrings = true)]
kenmerk hebben. Door contexten in te schakelenNullable
, begint MVC impliciet met het valideren van niet-nullable eigenschappen of parameters alsof ze zijn toegeschreven aan het [Required(AllowEmptyStrings = true)]
kenmerk. Houd rekening met de volgende code:
public class Person
{
public string Name { get; set; }
}
Als de app is gemaakt met <Nullable>enable</Nullable>
, resulteert een ontbrekende waarde Name
in een JSON- of formulierbericht in een validatiefout. Dit kan tegenstrijdig lijken omdat het [Required(AllowEmptyStrings = true)]
kenmerk wordt geïmpliceerd, maar dit is verwacht gedrag omdat lege tekenreeksen standaard worden geconverteerd naar null. Gebruik een verwijzingstype dat null kan worden gebruikt om null- of ontbrekende waarden op te geven voor de Name
eigenschap:
public class Person
{
public string? Name { get; set; }
}
Dit gedrag kan worden uitgeschakeld door het volgende te SuppressImplicitRequiredAttributeForNonNullableReferenceTypes configureren:Program.cs
builder.Services.AddControllers(
options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true);
[Vereist] validatie op de server
Op de server wordt een vereiste waarde als ontbrekend beschouwd als de eigenschap null is. Een niet-nullable veld is altijd geldig en het foutbericht van het [Required]
kenmerk wordt nooit weergegeven.
Modelbinding voor een niet-nullable eigenschap kan echter mislukken, wat resulteert in een foutbericht zoals The value '' is invalid
. Als u een aangepast foutbericht wilt opgeven voor validatie aan de serverzijde van niet-nullable typen, hebt u de volgende opties:
Het veld null maken (bijvoorbeeld
decimal?
in plaats vandecimal
). Null-waarde<T-waardetypen> worden behandeld als standaard null-typen.Geef het standaardfoutbericht op dat moet worden gebruikt door modelbinding, zoals wordt weergegeven in het volgende voorbeeld:
builder.Services.AddRazorPages() .AddMvcOptions(options => { options.MaxModelValidationErrors = 50; options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor( _ => "The field is required."); }); builder.Services.AddSingleton <IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
Zie voor meer informatie over modelbindingsfouten waarvoor u standaardberichten DefaultModelBindingMessageProviderkunt instellen.
[Vereist] validatie op de client
Niet-nullable typen en tekenreeksen worden anders verwerkt op de client in vergelijking met de server. Op de client:
- Een waarde wordt alleen als aanwezig beschouwd als er invoer voor wordt ingevoerd. Validatie aan de clientzijde verwerkt daarom niet-null-typen die hetzelfde zijn als null-typen.
- Witruimte in een tekenreeksveld wordt beschouwd als geldige invoer door de vereiste methode jQuery-validatie. Validatie aan de serverzijde beschouwt een vereist tekenreeksveld ongeldig als er alleen witruimte wordt ingevoerd.
Zoals eerder vermeld, worden niet-null-typen behandeld alsof ze een [Required(AllowEmptyStrings = true)]
kenmerk hadden. Dat betekent dat u validatie aan de clientzijde krijgt, zelfs als u het [Required(AllowEmptyStrings = true)]
kenmerk niet toepast. Maar als u het kenmerk niet gebruikt, krijgt u een standaardfoutbericht. Als u een aangepast foutbericht wilt opgeven, gebruikt u het kenmerk.
[Remote] attribute
Het kenmerk [Remote] implementeert validatie aan de clientzijde waarvoor een methode op de server moet worden aangeroepen om te bepalen of veldinvoer geldig is. De app moet bijvoorbeeld controleren of een gebruikersnaam al in gebruik is.
Externe validatie implementeren:
Maak een actiemethode om JavaScript aan te roepen. De externe methode jQuery Validation verwacht een JSON-antwoord:
-
true
betekent dat de invoergegevens geldig zijn. -
false
,undefined
ofnull
betekent dat de invoer ongeldig is. Het standaardfoutbericht weergeven. - Elke andere tekenreeks betekent dat de invoer ongeldig is. De tekenreeks weergeven als een aangepast foutbericht.
Hier volgt een voorbeeld van een actiemethode die een aangepast foutbericht retourneert:
[AcceptVerbs("GET", "POST")] public IActionResult VerifyEmail(string email) { if (!_userService.VerifyEmail(email)) { return Json($"Email {email} is already in use."); } return Json(true); }
-
Maak in de modelklasse aantekeningen op de eigenschap met een
[Remote]
kenmerk dat verwijst naar de validatieactiemethode, zoals wordt weergegeven in het volgende voorbeeld:[Remote(action: "VerifyEmail", controller: "Users")] public string Email { get; set; } = null!;
Validatie aan de serverzijde moet ook worden geïmplementeerd voor clients die JavaScript hebben uitgeschakeld.
Additional fields
Met AdditionalFields de eigenschap van het [Remote]
kenmerk kunt u combinaties van velden valideren op basis van gegevens op de server. Als het User
model bijvoorbeeld eigenschappen had en LastName
eigenschappen hadFirstName
, wilt u mogelijk controleren of bestaande gebruikers die twee namen al hebben. In het volgende voorbeeld ziet u hoe u AdditionalFields
gebruikt:
[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(LastName))]
[Display(Name = "First Name")]
public string FirstName { get; set; } = null!;
[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(FirstName))]
[Display(Name = "Last Name")]
public string LastName { get; set; } = null!;
AdditionalFields
kan expliciet worden ingesteld op de tekenreeksen FirstName en LastName, maar het gebruik van de operator nameof vereenvoudigt later herstructureren. De actiemethode voor deze validatie moet beide firstName
en lastName
argumenten accepteren:
[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);
}
Wanneer de gebruiker een voor- of achternaam invoert, voert JavaScript een externe aanroep uit om te zien of dat paar namen is gebruikt.
Als u twee of meer extra velden wilt valideren, geeft u deze op als een door komma's gescheiden lijst. Als u bijvoorbeeld een MiddleName
eigenschap wilt toevoegen aan het model, stelt u het [Remote]
kenmerk in zoals wordt weergegeven in het volgende voorbeeld:
[Remote(action: "VerifyName", controller: "Users",
AdditionalFields = nameof(FirstName) + "," + nameof(LastName))]
public string MiddleName { get; set; }
AdditionalFields
, net als alle kenmerkargumenten, moet een constante expressie zijn. Gebruik daarom geen geïnterpoleerde tekenreeks of aanroep Join om te initialiseren AdditionalFields
.
Alternatieven voor ingebouwde kenmerken
Als u validatie niet hebt opgegeven door ingebouwde kenmerken, kunt u het volgende doen:
Custom attributes
Voor scenario's die de ingebouwde validatiekenmerken niet verwerken, kunt u aangepaste validatiekenmerken maken. Maak een klasse die de ValidationAttributemethode overschrijft en overschrijft IsValid .
De IsValid
methode accepteert een object met de naamwaarde. Dit is de invoer die moet worden gevalideerd. Een overbelasting accepteert ook een ValidationContext object, dat aanvullende informatie biedt, zoals het modelexemplaren dat is gemaakt door modelbinding.
In het volgende voorbeeld wordt gecontroleerd of de releasedatum voor een film in het klassieke genre niet later is dan een bepaald jaar. Het [ClassicMovie]
kenmerk:
- Wordt alleen uitgevoerd op de server.
- Voor klassieke films valideert u de releasedatum:
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;
}
}
De movie
variabele in het voorgaande voorbeeld vertegenwoordigt een Movie
object dat de gegevens van de inzending van het formulier bevat. Wanneer de validatie mislukt, wordt een ValidationResult foutbericht geretourneerd.
IValidatableObject
Het voorgaande voorbeeld werkt alleen met Movie
typen. Een andere optie voor validatie op klasseniveau is om te implementeren IValidatableObject in de modelklasse, zoals wordt weergegeven in het volgende voorbeeld:
public class ValidatableMovie : IValidatableObject
{
private const int _classicYear = 1960;
public int Id { get; set; }
[Required]
[StringLength(100)]
public string Title { get; set; } = null!;
[DataType(DataType.Date)]
[Display(Name = "Release Date")]
public DateTime ReleaseDate { get; set; }
[Required]
[StringLength(1000)]
public string Description { get; set; } = null!;
[Range(0, 999.99)]
public decimal Price { get; set; }
public Genre Genre { get; set; }
public bool Preorder { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (Genre == Genre.Classic && ReleaseDate.Year > _classicYear)
{
yield return new ValidationResult(
$"Classic movies must have a release year no later than {_classicYear}.",
new[] { nameof(ReleaseDate) });
}
}
}
Custom validation
De volgende code laat zien hoe u een modelfout toevoegt nadat u het model hebt onderzocht:
if (Contact.Name == Contact.ShortName)
{
ModelState.AddModelError("Contact.ShortName",
"Short name can't be the same as Name.");
}
Met de volgende code wordt de validatietest geïmplementeerd in een controller:
if (contact.Name == contact.ShortName)
{
ModelState.AddModelError(nameof(contact.ShortName),
"Short name can't be the same as Name.");
}
Met de volgende code wordt gecontroleerd of het telefoonnummer en e-mailadres uniek zijn:
public async Task<IActionResult> OnPostAsync()
{
// Attach Validation Error Message to the Model on validation failure.
if (Contact.Name == Contact.ShortName)
{
ModelState.AddModelError("Contact.ShortName",
"Short name can't be the same as Name.");
}
if (_context.Contact.Any(i => i.PhoneNumber == Contact.PhoneNumber))
{
ModelState.AddModelError("Contact.PhoneNumber",
"The Phone number is already in use.");
}
if (_context.Contact.Any(i => i.Email == Contact.Email))
{
ModelState.AddModelError("Contact.Email", "The Email is already in use.");
}
if (!ModelState.IsValid || _context.Contact == null || Contact == null)
{
// if model is invalid, return the page with the model state errors.
return Page();
}
_context.Contact.Add(Contact);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
Met de volgende code wordt de validatietest geïmplementeerd in een controller:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Name,ShortName,Email,PhoneNumber")] Contact contact)
{
// Attach Validation Error Message to the Model on validation failure.
if (contact.Name == contact.ShortName)
{
ModelState.AddModelError(nameof(contact.ShortName),
"Short name can't be the same as Name.");
}
if (_context.Contact.Any(i => i.PhoneNumber == contact.PhoneNumber))
{
ModelState.AddModelError(nameof(contact.PhoneNumber),
"The Phone number is already in use.");
}
if (_context.Contact.Any(i => i.Email == contact.Email))
{
ModelState.AddModelError(nameof(contact.Email), "The Email is already in use.");
}
if (ModelState.IsValid)
{
_context.Add(contact);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(contact);
}
Het controleren op een uniek telefoonnummer of e-mailbericht wordt meestal ook uitgevoerd met externe validatie.
ValidationResult
Houd rekening met het volgende aangepaste ValidateNameAttribute
:
public class ValidateNameAttribute : ValidationAttribute
{
public ValidateNameAttribute()
{
const string defaultErrorMessage = "Error with Name";
ErrorMessage ??= defaultErrorMessage;
}
protected override ValidationResult? IsValid(object? value,
ValidationContext validationContext)
{
if (value == null || string.IsNullOrWhiteSpace(value.ToString()))
{
return new ValidationResult("Name is required.");
}
if (value.ToString()!.ToLower().Contains("zz"))
{
return new ValidationResult(
FormatErrorMessage(validationContext.DisplayName));
}
return ValidationResult.Success;
}
}
In de volgende code wordt het aangepaste [ValidateName]
kenmerk toegepast:
public class Contact
{
public Guid Id { get; set; }
[ValidateName(ErrorMessage = "Name must not contain `zz`")]
public string? Name { get; set; }
public string? Email { get; set; }
public string? PhoneNumber { get; set; }
}
Wanneer het model bevat zz
, wordt er een nieuw ValidationResult geretourneerd.
Knooppuntvalidatie op het hoogste niveau
Knooppunten op het hoogste niveau zijn onder andere:
- Action parameters
- Controller properties
- Parameters voor pagina-handler
- Eigenschappen van paginamodel
Modelgebonden knooppunten op het hoogste niveau worden gevalideerd naast het valideren van modeleigenschappen. In het volgende voorbeeld van de voorbeeld-app gebruikt de VerifyPhone
methode om RegularExpressionAttribute de phone
actieparameter te valideren:
[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);
}
Knooppunten op het hoogste niveau kunnen worden gebruikt BindRequiredAttribute met validatiekenmerken. In het volgende voorbeeld uit de voorbeeld-app geeft de CheckAge
methode aan dat de age
parameter moet worden gebonden aan de querytekenreeks wanneer het formulier wordt verzonden:
[HttpPost]
public IActionResult CheckAge([BindRequired, FromQuery] int age)
{
Op de pagina Leeftijd controleren (CheckAge.cshtml
) zijn er twee formulieren. Het eerste formulier verzendt een Age
waarde van 99
als een querytekenreeksparameter: https://localhost:5001/Users/CheckAge?Age=99
.
Wanneer een correct opgemaakte age
parameter uit de querytekenreeks wordt verzonden, wordt het formulier gevalideerd.
Het tweede formulier op de pagina Leeftijd controleren verzendt de Age
waarde in de hoofdtekst van de aanvraag en de validatie mislukt. Binding mislukt omdat de age
parameter afkomstig moet zijn van een queryreeks.
Maximum errors
Validatie stopt wanneer het maximum aantal fouten is bereikt (standaard 200). U kunt dit nummer configureren met de volgende code in Program.cs
:
builder.Services.AddRazorPages()
.AddMvcOptions(options =>
{
options.MaxModelValidationErrors = 50;
options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
_ => "The field is required.");
});
builder.Services.AddSingleton
<IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
Maximum recursion
ValidationVisitor doorkruist de objectgrafiek van het model dat wordt gevalideerd. Voor modellen die diep zijn of oneindig recursief zijn, kan validatie leiden tot stackoverloop.
MvcOptions.MaxValidationDepth biedt een manier om validatie vroeg te stoppen als de bezoeker een geconfigureerde diepte overschrijdt. De standaardwaarde is MvcOptions.MaxValidationDepth
32.
Automatic short-circuit
Validatie wordt automatisch kortsluiting (overgeslagen) als de modelgrafiek geen validatie vereist. Objecten waarvoor de runtime validatie overslaat voor verzamelingen primitieven (zoals byte[]
, string[]
, Dictionary<string, string>
) en complexe objectgrafieken die geen geldige gegevens bevatten.
Client-side validation
Validatie aan de clientzijde voorkomt verzending totdat het formulier geldig is. Met de knop Verzenden wordt JavaScript uitgevoerd waarmee het formulier wordt verzonden of foutberichten worden weergegeven.
Validatie aan de clientzijde voorkomt een onnodige retour naar de server wanneer er invoerfouten zijn op een formulier. De volgende scriptverwijzingen in validatie _Layout.cshtml
aan de clientzijde en _ValidationScriptsPartial.cshtml
ondersteunen deze:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.3/jquery.validate.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.12/jquery.validate.unobtrusive.js"></script>
Het jQuery Unobtrusive Validation-script is een aangepaste Microsoft front-endbibliotheek die voortbouwt op de populaire jQuery Validation-invoegtoepassing . Zonder jQuery Unobtrusive Validation moet u dezelfde validatielogica op twee plaatsen codeeren: eenmaal in de validatiekenmerken aan de serverzijde van modeleigenschappen en vervolgens opnieuw in scripts aan de clientzijde.
Tag Helpers en HTML-helpers gebruiken in plaats daarvan de validatiekenmerken en typ metagegevens van modeleigenschappen om HTML 5-kenmerken data-
weer te geven voor de formulierelementen die moeten worden gevalideerd. jQuery Unobtrusive Validation parseert de data-
kenmerken en geeft de logica door aan jQuery Validation, waardoor de validatielogica aan de serverzijde wordt gekopieerd naar de client. U kunt validatiefouten op de client weergeven met behulp van taghelpers, zoals hier wordt weergegeven:
<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>
De voorgaande tag-helpers geven de volgende HTML weer:
<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>
U ziet dat de data-
kenmerken in de HTML-uitvoer overeenkomen met de validatiekenmerken voor de Movie.ReleaseDate
eigenschap. Het data-val-required
kenmerk bevat een foutbericht dat moet worden weergegeven als de gebruiker het veld releasedatum niet invult. jQuery Unobtrusive Validation geeft deze waarde door aan de methode jQuery Validation required(), die dat bericht vervolgens weergeeft in het bijbehorende <spanelement> .
Validatie van gegevenstypen is gebaseerd op het .NET-type van een eigenschap, tenzij dat wordt overschreven door een [DataType] -kenmerk. Browsers hebben hun eigen standaardfoutberichten, maar het jQuery Validation Unobtrusive Validation Package kan deze berichten overschrijven.
[DataType]
met kenmerken en subklassen zoals [EmailAddress] kunt u het foutbericht opgeven.
Unobtrusive validation
Zie dit GitHub-probleem voor informatie over onopvallende validatie.
Validatie toevoegen aan dynamische formulieren
jQuery Unobtrusive Validation geeft validatielogica en parameters door aan jQuery-validatie wanneer de pagina voor het eerst wordt geladen. Validatie werkt daarom niet automatisch voor dynamisch gegenereerde formulieren. Als u validatie wilt inschakelen, vertelt u jQuery Unobtrusive Validation om het dynamische formulier direct te parseren nadat u het hebt gemaakt. Met de volgende code wordt bijvoorbeeld validatie aan de clientzijde ingesteld op een formulier dat via AJAX is toegevoegd.
$.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);
}
})
De $.validator.unobtrusive.parse()
methode accepteert een jQuery-selector voor het ene argument. Deze methode vertelt jQuery Unobtrusive Validation om de data-
kenmerken van formulieren in die selector te parseren. De waarden van deze kenmerken worden vervolgens doorgegeven aan de jQuery Validation-invoegtoepassing.
Validatie toevoegen aan dynamische besturingselementen
De $.validator.unobtrusive.parse()
methode werkt op een heel formulier, niet op afzonderlijke dynamisch gegenereerde besturingselementen, zoals <input>
en <select/>
. Als u het formulier opnieuw wilt parseren, verwijdert u de validatiegegevens die zijn toegevoegd toen het formulier eerder werd geparseerd, zoals wordt weergegeven in het volgende voorbeeld:
$.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);
}
})
Validatie aan de clientzijde
Aangepaste validatie aan de clientzijde wordt uitgevoerd door HTML-kenmerken te genereren data-
die werken met een aangepaste jQuery-validatieadapter. De volgende voorbeeldadaptercode is geschreven voor de [ClassicMovie]
kenmerken die [ClassicMovieWithClientValidator]
eerder in dit artikel zijn geïntroduceerd:
$.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;
});
Zie de documentatie voor jQuery-validatie voor informatie over het schrijven van adapters.
Het gebruik van een adapter voor een bepaald veld wordt geactiveerd door data-
kenmerken die:
- Markeer het veld als onderworpen aan validatie (
data-val="true"
). - Identificeer de naam van een validatieregel en de tekst van het foutbericht (bijvoorbeeld
data-val-rulename="Error message."
). - Geef eventuele aanvullende parameters op die de validator nodig heeft (bijvoorbeeld
data-val-rulename-param1="value"
).
In het volgende voorbeeld ziet u de data-
kenmerken voor het kenmerk van ClassicMovie
de voorbeeld-app:
<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="">
Zoals eerder vermeld, gebruiken Tag Helpers en HTML-helpers informatie uit validatiekenmerken om kenmerken weer te geven data-
. Er zijn twee opties voor het schrijven van code die resulteert in het maken van aangepaste data-
HTML-kenmerken:
- Maak een klasse die is afgeleid van AttributeAdapterBase<TAttribute> en een klasse die implementeert IValidationAttributeAdapterProvider, en registreer uw kenmerk en de bijbehorende adapter in DI. Deze methode volgt het principe van één verantwoordelijkheid in dat servergerelateerde en clientgerelateerde validatiecode zich in afzonderlijke klassen bevindt. De adapter heeft ook het voordeel dat omdat deze is geregistreerd in DI, andere services in DI beschikbaar zijn indien nodig.
- Implementeren IClientModelValidator in uw ValidationAttribute klas. Deze methode is mogelijk geschikt als het kenmerk geen validatie aan de serverzijde uitvoert en geen services van DI nodig heeft.
AttributeAdapter voor validatie aan clientzijde
Deze methode voor het weergeven data-
van kenmerken in HTML wordt gebruikt door het ClassicMovie
kenmerk in de voorbeeld-app. Clientvalidatie toevoegen met behulp van deze methode:
Maak een kenmerkadapterklasse voor het aangepaste validatiekenmerk. De klasse afleiden van AttributeAdapterBase<TAttribute>. Maak een
AddValidation
methode waarmee kenmerken worden toegevoegddata-
aan de weergegeven uitvoer, zoals wordt weergegeven in dit voorbeeld: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(); }
Maak een adapterproviderklasse die wordt geïmplementeerd IValidationAttributeAdapterProvider. Geef in de GetAttributeAdapter methode het aangepaste kenmerk door aan de constructor van de adapter, zoals wordt weergegeven in dit voorbeeld:
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); } }
Registreer de adapterprovider voor DI in
Program.cs
:builder.Services.AddRazorPages() .AddMvcOptions(options => { options.MaxModelValidationErrors = 50; options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor( _ => "The field is required."); }); builder.Services.AddSingleton <IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
IClientModelValidator voor validatie aan clientzijde
Deze methode voor het weergeven data-
van kenmerken in HTML wordt gebruikt door het ClassicMovieWithClientValidator
kenmerk in de voorbeeld-app. Clientvalidatie toevoegen met behulp van deze methode:
Implementeer de IClientModelValidator interface in het aangepaste validatiekenmerk en maak een AddValidation methode. Voeg in de
AddValidation
methode kenmerken toedata-
voor validatie, zoals wordt weergegeven in het volgende voorbeeld:public class ClassicMovieWithClientValidatorAttribute : ValidationAttribute, IClientModelValidator { public ClassicMovieWithClientValidatorAttribute(int year) => Year = year; public int Year { get; } public void AddValidation(ClientModelValidationContext context) { MergeAttribute(context.Attributes, "data-val", "true"); MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage()); var year = Year.ToString(CultureInfo.InvariantCulture); MergeAttribute(context.Attributes, "data-val-classicmovie-year", year); } public string GetErrorMessage() => $"Classic movies must have a release year no later than {Year}."; protected override ValidationResult? IsValid( object? value, ValidationContext validationContext) { var movie = (Movie)validationContext.ObjectInstance; var releaseYear = ((DateTime)value!).Year; if (movie.Genre == Genre.Classic && releaseYear > Year) { return new ValidationResult(GetErrorMessage()); } return ValidationResult.Success; } private static bool MergeAttribute(IDictionary<string, string> attributes, string key, string value) { if (attributes.ContainsKey(key)) { return false; } attributes.Add(key, value); return true; } }
Validatie aan clientzijde uitschakelen
Met de volgende code wordt clientvalidatie in Razor Pages uitgeschakeld:
builder.Services.AddRazorPages()
.AddViewOptions(options =>
{
options.HtmlHelperOptions.ClientValidationEnabled = false;
});
Andere opties voor het uitschakelen van validatie aan clientzijde:
- Markeer de verwijzing
_ValidationScriptsPartial
in alle.cshtml
bestanden als commentaar. - Verwijder de inhoud van het bestand Pages\Shared_ValidationScriptsPartial.cshtml .
De voorgaande benadering voorkomt geen validatie aan de clientzijde van ASP.NET Core-klassebibliotheek IdentityRazor . Zie Scaffold Identity in ASP.NET Core-projectenvoor meer informatie.
Problem details
Probleemdetails zijn niet de enige antwoordindeling voor het beschrijven van een HTTP-API-fout. Ze worden echter vaak gebruikt om fouten voor HTTP-API's te rapporteren.
De service met probleemdetails implementeert de IProblemDetailsService interface, die ondersteuning biedt voor het maken van probleemdetails in ASP.NET Core. De AddProblemDetails(IServiceCollection)-extensiemethode op IServiceCollection registreert de standaard IProblemDetailsService
-implementatie.
In ASP.NET Core-apps genereert de volgende middleware problemoplossings-HTTP-antwoorden wanneer AddProblemDetails
wordt aangeroepen, behalve wanneer de Accept
request-HTTP-header geen van de inhoudstypen bevat die worden ondersteund door de geregistreerde IProblemDetailsWriter (standaard: application/json
):
- ExceptionHandlerMiddleware: Genereert een antwoord met probleemdetails wanneer er geen aangepaste handler is gedefinieerd.
- StatusCodePagesMiddleware: genereert standaard een antwoord met details van het probleem.
-
DeveloperExceptionPageMiddleware: Genereert een probleemdetailreactie tijdens ontwikkeling wanneer de HTTP-header van de
Accept
aanvraagtext/html
niet bevat.
Additional resources
In dit artikel wordt uitgelegd hoe u gebruikersinvoer kunt valideren in een ASP.NET Core MVC- of Razor Pages-app.
Voorbeeldcode bekijken of downloaden (hoe u kunt downloaden).
Model state
De modelstatus vertegenwoordigt fouten die afkomstig zijn van twee subsystemen: modelbinding en modelvalidatie. Fouten die afkomstig zijn van modelbinding zijn over het algemeen fouten bij het converteren van gegevens. Een 'x' wordt bijvoorbeeld ingevoerd in een geheel getalveld. Modelvalidatie vindt plaats na modelbinding en rapporteert fouten waarbij gegevens niet voldoen aan bedrijfsregels. Een 0 wordt bijvoorbeeld ingevoerd in een veld waarin een classificatie tussen 1 en 5 wordt verwacht.
Zowel modelbinding als modelvalidatie vinden plaats vóór de uitvoering van een controlleractie of een Razor Pagina-handlermethode. Voor web-apps is het de verantwoordelijkheid van de app om op de juiste wijze te controleren ModelState.IsValid
en erop te reageren. Web-apps worden de pagina meestal opnieuw weergegeven met een foutbericht, zoals wordt weergegeven in het volgende Razor paginavoorbeeld:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movies.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
Voor ASP.NET Core MVC met controllers en weergaven ziet u in het volgende voorbeeld hoe u binnen een controlleractie kunt controleren ModelState.IsValid
:
public async Task<IActionResult> Create(Movie movie)
{
if (!ModelState.IsValid)
{
return View(movie);
}
_context.Movies.Add(movie);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
Web-API-controllers hoeven niet te controleren ModelState.IsValid
of ze het kenmerk [ApiController] hebben. In dat geval wordt een automatisch HTTP 400-antwoord met foutdetails geretourneerd wanneer de modelstatus ongeldig is. Zie Automatische HTTP 400-antwoordenvoor meer informatie.
Rerun validation
Validatie is automatisch, maar u wilt deze mogelijk handmatig herhalen. U kunt bijvoorbeeld een waarde voor een eigenschap berekenen en de validatie opnieuw uitvoeren nadat u de eigenschap hebt ingesteld op de berekende waarde. Als u de validatie opnieuw wilt uitvoeren, roept ModelStateDictionary.ClearValidationState u aan om de validatie te wissen die specifiek is voor het model dat wordt gevalideerd, gevolgd door 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");
}
Validation attributes
Met validatiekenmerken kunt u validatieregels opgeven voor modeleigenschappen. In het volgende voorbeeld uit de voorbeeld-app ziet u een modelklasse die is geannoteerd met validatiekenmerken. Het [ClassicMovie]
kenmerk is een aangepast validatiekenmerk en de andere kenmerken zijn ingebouwd. Niet weergegeven is [ClassicMovieWithClientValidator]
, wat een alternatieve manier toont om een aangepast kenmerk te implementeren.
public class Movie
{
public int Id { get; set; }
[Required]
[StringLength(100)]
public string Title { get; set; } = null!;
[ClassicMovie(1960)]
[DataType(DataType.Date)]
[Display(Name = "Release Date")]
public DateTime ReleaseDate { get; set; }
[Required]
[StringLength(1000)]
public string Description { get; set; } = null!;
[Range(0, 999.99)]
public decimal Price { get; set; }
public Genre Genre { get; set; }
public bool Preorder { get; set; }
}
Built-in attributes
Hier volgen enkele ingebouwde validatiekenmerken:
- [ValidateNever]: geeft aan dat een eigenschap of parameter moet worden uitgesloten van validatie.
- [CreditCard]: valideert of de eigenschap een creditcardindeling heeft. Hiervoor zijn aanvullende methoden voor jQuery-validatie vereist.
- [Vergelijken]: valideert dat twee eigenschappen in een model overeenkomen.
- [EmailAddress]: valideert of de eigenschap een e-mailindeling heeft.
- [Telefoon]: controleert of de eigenschap een telefoonnummernotatie heeft.
- [Bereik]: valideert of de eigenschapswaarde binnen een opgegeven bereik valt.
- [RegularExpression]: valideert of de eigenschapswaarde overeenkomt met een opgegeven reguliere expressie.
-
[Vereist]: valideert dat het veld niet null is. Zie
[Required]
het kenmerk voor meer informatie over het gedrag van dit kenmerk. - [StringLength]: hiermee wordt gevalideerd dat een waarde van een tekenreekseigenschap geen opgegeven lengtelimiet overschrijdt.
- [Url]: valideert of de eigenschap een URL-indeling heeft.
-
[Extern]: valideert invoer op de client door een actiemethode op de server aan te roepen. Zie
[Remote]
het kenmerk voor meer informatie over het gedrag van dit kenmerk.
Een volledige lijst met validatiekenmerken vindt u in de System.ComponentModel.DataAnnotations naamruimte.
Error messages
Met validatiekenmerken kunt u het foutbericht opgeven dat moet worden weergegeven voor ongeldige invoer. For example:
[StringLength(8, ErrorMessage = "Name length can't be more than 8.")]
Intern worden de kenmerken aangeroepen String.Format met een tijdelijke aanduiding voor de veldnaam en soms aanvullende tijdelijke aanduidingen. For example:
[StringLength(8, ErrorMessage = "{0} length must be between {2} and {1}.", MinimumLength = 6)]
Wanneer het wordt toegepast op een Name
eigenschap, is het foutbericht dat door de voorgaande code is gemaakt, de naamlengte moet tussen 6 en 8 zijn.
Als u wilt zien aan welke parameters worden doorgegeven String.Format
voor het foutbericht van een bepaald kenmerk, raadpleegt u de broncode van DataAnnotations.
Niet-null-verwijzingstypen en het kenmerk [Vereist]
Het validatiesysteem behandelt niet-nullable parameters of afhankelijke eigenschappen alsof ze een [Required(AllowEmptyStrings = true)]
kenmerk hebben. Door contexten in te schakelenNullable
, begint MVC impliciet met het valideren van niet-nullable eigenschappen voor niet-generieke typen of parameters alsof ze aan het [Required(AllowEmptyStrings = true)]
kenmerk zijn toegeschreven. Houd rekening met de volgende code:
public class Person
{
public string Name { get; set; }
}
Als de app is gemaakt met <Nullable>enable</Nullable>
, resulteert een ontbrekende waarde Name
in een JSON- of formulierbericht in een validatiefout. Gebruik een verwijzingstype dat null kan worden gebruikt om null- of ontbrekende waarden op te geven voor de Name
eigenschap:
public class Person
{
public string? Name { get; set; }
}
Dit gedrag kan worden uitgeschakeld door het volgende te SuppressImplicitRequiredAttributeForNonNullableReferenceTypes configureren:Program.cs
builder.Services.AddControllers(
options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true);
Niet-null-eigenschappen voor algemene typen en kenmerk [Vereist]
Niet-null-eigenschappen voor algemene typen moeten het [Required]
kenmerk bevatten wanneer het type is vereist. In de volgende code TestRequired
is niet vereist:
public class WeatherForecast<T>
{
public string TestRequired { get; set; } = null!;
public T? Inner { get; set; }
}
In de volgende code TestRequired
wordt expliciet gemarkeerd als vereist:
using System.ComponentModel.DataAnnotations;
public class WeatherForecast<T>
{
[Required]
public string TestRequired { get; set; } = null!;
public T? Inner { get; set; }
}
[Vereist] validatie op de server
Op de server wordt een vereiste waarde als ontbrekend beschouwd als de eigenschap null is. Een niet-nullable veld is altijd geldig en het foutbericht van het [Required]
kenmerk wordt nooit weergegeven.
Modelbinding voor een niet-nullable eigenschap kan echter mislukken, wat resulteert in een foutbericht zoals The value '' is invalid
. Als u een aangepast foutbericht wilt opgeven voor validatie aan de serverzijde van niet-nullable typen, hebt u de volgende opties:
Het veld null maken (bijvoorbeeld
decimal?
in plaats vandecimal
). Null-waarde<T-waardetypen> worden behandeld als standaard null-typen.Geef het standaardfoutbericht op dat moet worden gebruikt door modelbinding, zoals wordt weergegeven in het volgende voorbeeld:
builder.Services.AddRazorPages() .AddMvcOptions(options => { options.MaxModelValidationErrors = 50; options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor( _ => "The field is required."); }); builder.Services.AddSingleton <IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
Zie voor meer informatie over modelbindingsfouten waarvoor u standaardberichten DefaultModelBindingMessageProviderkunt instellen.
[Vereist] validatie op de client
Niet-nullable typen en tekenreeksen worden anders verwerkt op de client in vergelijking met de server. Op de client:
- Een waarde wordt alleen als aanwezig beschouwd als er invoer voor wordt ingevoerd. Validatie aan de clientzijde verwerkt daarom niet-null-typen die hetzelfde zijn als null-typen.
- Witruimte in een tekenreeksveld wordt beschouwd als geldige invoer door de vereiste methode jQuery-validatie. Validatie aan de serverzijde beschouwt een vereist tekenreeksveld ongeldig als er alleen witruimte wordt ingevoerd.
Zoals eerder vermeld, worden niet-null-typen behandeld alsof ze een [Required(AllowEmptyStrings = true)]
kenmerk hadden. Dat betekent dat u validatie aan de clientzijde krijgt, zelfs als u het [Required(AllowEmptyStrings = true)]
kenmerk niet toepast. Maar als u het kenmerk niet gebruikt, krijgt u een standaardfoutbericht. Als u een aangepast foutbericht wilt opgeven, gebruikt u het kenmerk.
[Remote] attribute
Het kenmerk [Remote] implementeert validatie aan de clientzijde waarvoor een methode op de server moet worden aangeroepen om te bepalen of veldinvoer geldig is. De app moet bijvoorbeeld controleren of een gebruikersnaam al in gebruik is.
Externe validatie implementeren:
Maak een actiemethode om JavaScript aan te roepen. De externe methode jQuery Validation verwacht een JSON-antwoord:
-
true
betekent dat de invoergegevens geldig zijn. -
false
,undefined
ofnull
betekent dat de invoer ongeldig is. Het standaardfoutbericht weergeven. - Elke andere tekenreeks betekent dat de invoer ongeldig is. De tekenreeks weergeven als een aangepast foutbericht.
Hier volgt een voorbeeld van een actiemethode die een aangepast foutbericht retourneert:
[AcceptVerbs("GET", "POST")] public IActionResult VerifyEmail(string email) { if (!_userService.VerifyEmail(email)) { return Json($"Email {email} is already in use."); } return Json(true); }
-
Maak in de modelklasse aantekeningen op de eigenschap met een
[Remote]
kenmerk dat verwijst naar de validatieactiemethode, zoals wordt weergegeven in het volgende voorbeeld:[Remote(action: "VerifyEmail", controller: "Users")] public string Email { get; set; } = null!;
Additional fields
Met AdditionalFields de eigenschap van het [Remote]
kenmerk kunt u combinaties van velden valideren op basis van gegevens op de server. Als het User
model bijvoorbeeld eigenschappen had en LastName
eigenschappen hadFirstName
, wilt u mogelijk controleren of bestaande gebruikers die twee namen al hebben. In het volgende voorbeeld ziet u hoe u AdditionalFields
gebruikt:
[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(LastName))]
[Display(Name = "First Name")]
public string FirstName { get; set; } = null!;
[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(FirstName))]
[Display(Name = "Last Name")]
public string LastName { get; set; } = null!;
AdditionalFields
kan expliciet worden ingesteld op de tekenreeksen FirstName en LastName, maar het gebruik van de operator nameof vereenvoudigt later herstructureren. De actiemethode voor deze validatie moet beide firstName
en lastName
argumenten accepteren:
[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);
}
Wanneer de gebruiker een voor- of achternaam invoert, voert JavaScript een externe aanroep uit om te zien of dat paar namen is gebruikt.
Als u twee of meer extra velden wilt valideren, geeft u deze op als een door komma's gescheiden lijst. Als u bijvoorbeeld een MiddleName
eigenschap wilt toevoegen aan het model, stelt u het [Remote]
kenmerk in zoals wordt weergegeven in het volgende voorbeeld:
[Remote(action: "VerifyName", controller: "Users",
AdditionalFields = nameof(FirstName) + "," + nameof(LastName))]
public string MiddleName { get; set; }
AdditionalFields
, net als alle kenmerkargumenten, moet een constante expressie zijn. Gebruik daarom geen geïnterpoleerde tekenreeks of aanroep Join om te initialiseren AdditionalFields
.
Alternatieven voor ingebouwde kenmerken
Als u validatie niet hebt opgegeven door ingebouwde kenmerken, kunt u het volgende doen:
Custom attributes
Voor scenario's die de ingebouwde validatiekenmerken niet verwerken, kunt u aangepaste validatiekenmerken maken. Maak een klasse die de ValidationAttributemethode overschrijft en overschrijft IsValid .
De IsValid
methode accepteert een object met de naamwaarde. Dit is de invoer die moet worden gevalideerd. Een overbelasting accepteert ook een ValidationContext object, dat aanvullende informatie biedt, zoals het modelexemplaren dat is gemaakt door modelbinding.
In het volgende voorbeeld wordt gecontroleerd of de releasedatum voor een film in het klassieke genre niet later is dan een bepaald jaar. Het [ClassicMovie]
kenmerk:
- Wordt alleen uitgevoerd op de server.
- Voor klassieke films valideert u de releasedatum:
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;
}
}
De movie
variabele in het voorgaande voorbeeld vertegenwoordigt een Movie
object dat de gegevens van de inzending van het formulier bevat. Wanneer de validatie mislukt, wordt een ValidationResult foutbericht geretourneerd.
IValidatableObject
Het voorgaande voorbeeld werkt alleen met Movie
typen. Een andere optie voor validatie op klasseniveau is om te implementeren IValidatableObject in de modelklasse, zoals wordt weergegeven in het volgende voorbeeld:
public class ValidatableMovie : IValidatableObject
{
private const int _classicYear = 1960;
public int Id { get; set; }
[Required]
[StringLength(100)]
public string Title { get; set; } = null!;
[DataType(DataType.Date)]
[Display(Name = "Release Date")]
public DateTime ReleaseDate { get; set; }
[Required]
[StringLength(1000)]
public string Description { get; set; } = null!;
[Range(0, 999.99)]
public decimal Price { get; set; }
public Genre Genre { get; set; }
public bool Preorder { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (Genre == Genre.Classic && ReleaseDate.Year > _classicYear)
{
yield return new ValidationResult(
$"Classic movies must have a release year no later than {_classicYear}.",
new[] { nameof(ReleaseDate) });
}
}
}
Knooppuntvalidatie op het hoogste niveau
Knooppunten op het hoogste niveau zijn onder andere:
- Action parameters
- Controller properties
- Parameters voor pagina-handler
- Eigenschappen van paginamodel
Modelgebonden knooppunten op het hoogste niveau worden gevalideerd naast het valideren van modeleigenschappen. In het volgende voorbeeld van de voorbeeld-app gebruikt de VerifyPhone
methode om RegularExpressionAttribute de phone
actieparameter te valideren:
[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);
}
Knooppunten op het hoogste niveau kunnen worden gebruikt BindRequiredAttribute met validatiekenmerken. In het volgende voorbeeld uit de voorbeeld-app geeft de CheckAge
methode aan dat de age
parameter moet worden gebonden aan de querytekenreeks wanneer het formulier wordt verzonden:
[HttpPost]
public IActionResult CheckAge([BindRequired, FromQuery] int age)
{
Op de pagina Leeftijd controleren (CheckAge.cshtml
) zijn er twee formulieren. Het eerste formulier verzendt een Age
waarde van 99
als een querytekenreeksparameter: https://localhost:5001/Users/CheckAge?Age=99
.
Wanneer een correct opgemaakte age
parameter uit de querytekenreeks wordt verzonden, wordt het formulier gevalideerd.
Het tweede formulier op de pagina Leeftijd controleren verzendt de Age
waarde in de hoofdtekst van de aanvraag en de validatie mislukt. Binding mislukt omdat de age
parameter afkomstig moet zijn van een queryreeks.
Maximum errors
Validatie stopt wanneer het maximum aantal fouten is bereikt (standaard 200). U kunt dit nummer configureren met de volgende code in Program.cs
:
builder.Services.AddRazorPages()
.AddMvcOptions(options =>
{
options.MaxModelValidationErrors = 50;
options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
_ => "The field is required.");
});
builder.Services.AddSingleton
<IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
Maximum recursion
ValidationVisitor doorkruist de objectgrafiek van het model dat wordt gevalideerd. Voor modellen die diep zijn of oneindig recursief zijn, kan validatie leiden tot stackoverloop.
MvcOptions.MaxValidationDepth biedt een manier om validatie vroeg te stoppen als de bezoeker een geconfigureerde diepte overschrijdt. De standaardwaarde is MvcOptions.MaxValidationDepth
32.
Automatic short-circuit
Validatie wordt automatisch kortsluiting (overgeslagen) als de modelgrafiek geen validatie vereist. Objecten waarvoor de runtime validatie overslaat voor verzamelingen primitieven (zoals byte[]
, string[]
, Dictionary<string, string>
) en complexe objectgrafieken die geen geldige gegevens bevatten.
Client-side validation
Validatie aan de clientzijde voorkomt verzending totdat het formulier geldig is. Met de knop Verzenden wordt JavaScript uitgevoerd waarmee het formulier wordt verzonden of foutberichten worden weergegeven.
Validatie aan de clientzijde voorkomt een onnodige retour naar de server wanneer er invoerfouten zijn op een formulier. De volgende scriptverwijzingen in validatie _Layout.cshtml
aan de clientzijde en _ValidationScriptsPartial.cshtml
ondersteunen deze:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.3/jquery.validate.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.12/jquery.validate.unobtrusive.js"></script>
Het jQuery Unobtrusive Validation-script is een aangepaste Microsoft front-endbibliotheek die voortbouwt op de populaire jQuery Validation-invoegtoepassing . Zonder jQuery Unobtrusive Validation moet u dezelfde validatielogica op twee plaatsen codeeren: eenmaal in de validatiekenmerken aan de serverzijde van modeleigenschappen en vervolgens opnieuw in scripts aan de clientzijde.
Tag Helpers en HTML-helpers gebruiken in plaats daarvan de validatiekenmerken en typ metagegevens van modeleigenschappen om HTML 5-kenmerken data-
weer te geven voor de formulierelementen die moeten worden gevalideerd. jQuery Unobtrusive Validation parseert de data-
kenmerken en geeft de logica door aan jQuery Validation, waardoor de validatielogica aan de serverzijde wordt gekopieerd naar de client. U kunt validatiefouten op de client weergeven met behulp van taghelpers, zoals hier wordt weergegeven:
<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>
De voorgaande tag-helpers geven de volgende HTML weer:
<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>
U ziet dat de data-
kenmerken in de HTML-uitvoer overeenkomen met de validatiekenmerken voor de Movie.ReleaseDate
eigenschap. Het data-val-required
kenmerk bevat een foutbericht dat moet worden weergegeven als de gebruiker het veld releasedatum niet invult. jQuery Unobtrusive Validation geeft deze waarde door aan de methode jQuery Validation required(), die dat bericht vervolgens weergeeft in het bijbehorende <spanelement> .
Validatie van gegevenstypen is gebaseerd op het .NET-type van een eigenschap, tenzij dat wordt overschreven door een [DataType] -kenmerk. Browsers hebben hun eigen standaardfoutberichten, maar het jQuery Validation Unobtrusive Validation Package kan deze berichten overschrijven.
[DataType]
met kenmerken en subklassen zoals [EmailAddress] kunt u het foutbericht opgeven.
Unobtrusive validation
Zie dit GitHub-probleem voor informatie over onopvallende validatie.
Validatie toevoegen aan dynamische formulieren
jQuery Unobtrusive Validation geeft validatielogica en parameters door aan jQuery-validatie wanneer de pagina voor het eerst wordt geladen. Validatie werkt daarom niet automatisch voor dynamisch gegenereerde formulieren. Als u validatie wilt inschakelen, vertelt u jQuery Unobtrusive Validation om het dynamische formulier direct te parseren nadat u het hebt gemaakt. Met de volgende code wordt bijvoorbeeld validatie aan de clientzijde ingesteld op een formulier dat via AJAX is toegevoegd.
$.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);
}
})
De $.validator.unobtrusive.parse()
methode accepteert een jQuery-selector voor het ene argument. Deze methode vertelt jQuery Unobtrusive Validation om de data-
kenmerken van formulieren in die selector te parseren. De waarden van deze kenmerken worden vervolgens doorgegeven aan de jQuery Validation-invoegtoepassing.
Validatie toevoegen aan dynamische besturingselementen
De $.validator.unobtrusive.parse()
methode werkt op een heel formulier, niet op afzonderlijke dynamisch gegenereerde besturingselementen, zoals <input>
en <select/>
. Als u het formulier opnieuw wilt parseren, verwijdert u de validatiegegevens die zijn toegevoegd toen het formulier eerder werd geparseerd, zoals wordt weergegeven in het volgende voorbeeld:
$.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);
}
})
Validatie aan de clientzijde
Aangepaste validatie aan de clientzijde wordt uitgevoerd door HTML-kenmerken te genereren data-
die werken met een aangepaste jQuery-validatieadapter. De volgende voorbeeldadaptercode is geschreven voor de [ClassicMovie]
kenmerken die [ClassicMovieWithClientValidator]
eerder in dit artikel zijn geïntroduceerd:
$.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;
});
Zie de documentatie voor jQuery-validatie voor informatie over het schrijven van adapters.
Het gebruik van een adapter voor een bepaald veld wordt geactiveerd door data-
kenmerken die:
- Markeer het veld als onderworpen aan validatie (
data-val="true"
). - Identificeer de naam van een validatieregel en de tekst van het foutbericht (bijvoorbeeld
data-val-rulename="Error message."
). - Geef eventuele aanvullende parameters op die de validator nodig heeft (bijvoorbeeld
data-val-rulename-param1="value"
).
In het volgende voorbeeld ziet u de data-
kenmerken voor het kenmerk van ClassicMovie
de voorbeeld-app:
<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="">
Zoals eerder vermeld, gebruiken Tag Helpers en HTML-helpers informatie uit validatiekenmerken om kenmerken weer te geven data-
. Er zijn twee opties voor het schrijven van code die resulteert in het maken van aangepaste data-
HTML-kenmerken:
- Maak een klasse die is afgeleid van AttributeAdapterBase<TAttribute> en een klasse die implementeert IValidationAttributeAdapterProvider, en registreer uw kenmerk en de bijbehorende adapter in DI. Deze methode volgt het principe van één verantwoordelijkheid in dat servergerelateerde en clientgerelateerde validatiecode zich in afzonderlijke klassen bevindt. De adapter heeft ook het voordeel dat omdat deze is geregistreerd in DI, andere services in DI beschikbaar zijn indien nodig.
- Implementeren IClientModelValidator in uw ValidationAttribute klas. Deze methode is mogelijk geschikt als het kenmerk geen validatie aan de serverzijde uitvoert en geen services van DI nodig heeft.
AttributeAdapter voor validatie aan clientzijde
Deze methode voor het weergeven data-
van kenmerken in HTML wordt gebruikt door het ClassicMovie
kenmerk in de voorbeeld-app. Clientvalidatie toevoegen met behulp van deze methode:
Maak een kenmerkadapterklasse voor het aangepaste validatiekenmerk. De klasse afleiden van AttributeAdapterBase<TAttribute>. Maak een
AddValidation
methode waarmee kenmerken worden toegevoegddata-
aan de weergegeven uitvoer, zoals wordt weergegeven in dit voorbeeld: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(); }
Maak een adapterproviderklasse die wordt geïmplementeerd IValidationAttributeAdapterProvider. Geef in de GetAttributeAdapter methode het aangepaste kenmerk door aan de constructor van de adapter, zoals wordt weergegeven in dit voorbeeld:
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); } }
Registreer de adapterprovider voor DI in
Program.cs
:builder.Services.AddRazorPages() .AddMvcOptions(options => { options.MaxModelValidationErrors = 50; options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor( _ => "The field is required."); }); builder.Services.AddSingleton <IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
IClientModelValidator voor validatie aan clientzijde
Deze methode voor het weergeven data-
van kenmerken in HTML wordt gebruikt door het ClassicMovieWithClientValidator
kenmerk in de voorbeeld-app. Clientvalidatie toevoegen met behulp van deze methode:
Implementeer de IClientModelValidator interface in het aangepaste validatiekenmerk en maak een AddValidation methode. Voeg in de
AddValidation
methode kenmerken toedata-
voor validatie, zoals wordt weergegeven in het volgende voorbeeld:public class ClassicMovieWithClientValidatorAttribute : ValidationAttribute, IClientModelValidator { public ClassicMovieWithClientValidatorAttribute(int year) => Year = year; public int Year { get; } public void AddValidation(ClientModelValidationContext context) { MergeAttribute(context.Attributes, "data-val", "true"); MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage()); var year = Year.ToString(CultureInfo.InvariantCulture); MergeAttribute(context.Attributes, "data-val-classicmovie-year", year); } public string GetErrorMessage() => $"Classic movies must have a release year no later than {Year}."; protected override ValidationResult? IsValid( object? value, ValidationContext validationContext) { var movie = (Movie)validationContext.ObjectInstance; var releaseYear = ((DateTime)value!).Year; if (movie.Genre == Genre.Classic && releaseYear > Year) { return new ValidationResult(GetErrorMessage()); } return ValidationResult.Success; } private static bool MergeAttribute(IDictionary<string, string> attributes, string key, string value) { if (attributes.ContainsKey(key)) { return false; } attributes.Add(key, value); return true; } }
Validatie aan clientzijde uitschakelen
Met de volgende code wordt clientvalidatie in Razor Pages uitgeschakeld:
builder.Services.AddRazorPages()
.AddViewOptions(options =>
{
options.HtmlHelperOptions.ClientValidationEnabled = false;
});
Andere opties voor het uitschakelen van validatie aan clientzijde:
- Markeer de verwijzing
_ValidationScriptsPartial
in alle.cshtml
bestanden als commentaar. - Verwijder de inhoud van het bestand Pages\Shared_ValidationScriptsPartial.cshtml .
De voorgaande benadering voorkomt geen validatie aan de clientzijde van ASP.NET Core-klassebibliotheek IdentityRazor . Zie Scaffold Identity in ASP.NET Core-projectenvoor meer informatie.
Additional resources
In dit artikel wordt uitgelegd hoe u gebruikersinvoer kunt valideren in een ASP.NET Core MVC- of Razor Pages-app.
Voorbeeldcode bekijken of downloaden (hoe u kunt downloaden).
Model state
De modelstatus vertegenwoordigt fouten die afkomstig zijn van twee subsystemen: modelbinding en modelvalidatie. Fouten die afkomstig zijn van modelbinding zijn over het algemeen fouten bij het converteren van gegevens. Een 'x' wordt bijvoorbeeld ingevoerd in een geheel getalveld. Modelvalidatie vindt plaats na modelbinding en rapporteert fouten waarbij gegevens niet voldoen aan bedrijfsregels. Een 0 wordt bijvoorbeeld ingevoerd in een veld waarin een classificatie tussen 1 en 5 wordt verwacht.
Zowel modelbinding als modelvalidatie vinden plaats vóór de uitvoering van een controlleractie of een Razor Pagina-handlermethode. Voor web-apps is het de verantwoordelijkheid van de app om op de juiste wijze te controleren ModelState.IsValid
en erop te reageren. Web-apps worden de pagina meestal opnieuw weergegeven met een foutbericht:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movies.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
Web-API-controllers hoeven niet te controleren ModelState.IsValid
of ze het kenmerk [ApiController] hebben. In dat geval wordt een automatisch HTTP 400-antwoord met foutdetails geretourneerd wanneer de modelstatus ongeldig is. Zie Automatische HTTP 400-antwoordenvoor meer informatie.
Rerun validation
Validatie is automatisch, maar u wilt deze mogelijk handmatig herhalen. U kunt bijvoorbeeld een waarde voor een eigenschap berekenen en de validatie opnieuw uitvoeren nadat u de eigenschap hebt ingesteld op de berekende waarde. Als u de validatie opnieuw wilt uitvoeren, roept ModelStateDictionary.ClearValidationState u aan om de validatie te wissen die specifiek is voor het model dat wordt gevalideerd, gevolgd door 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");
}
Validation attributes
Met validatiekenmerken kunt u validatieregels opgeven voor modeleigenschappen. In het volgende voorbeeld uit de voorbeeld-app ziet u een modelklasse die is geannoteerd met validatiekenmerken. Het [ClassicMovie]
kenmerk is een aangepast validatiekenmerk en de andere kenmerken zijn ingebouwd. Niet weergegeven is [ClassicMovieWithClientValidator]
, wat een alternatieve manier toont om een aangepast kenmerk te implementeren.
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; }
}
Built-in attributes
Hier volgen enkele ingebouwde validatiekenmerken:
- [ValidateNever]: geeft aan dat een eigenschap of parameter moet worden uitgesloten van validatie.
- [CreditCard]: valideert of de eigenschap een creditcardindeling heeft. Hiervoor zijn aanvullende methoden voor jQuery-validatie vereist.
- [Vergelijken]: valideert dat twee eigenschappen in een model overeenkomen.
- [EmailAddress]: valideert of de eigenschap een e-mailindeling heeft.
- [Telefoon]: controleert of de eigenschap een telefoonnummernotatie heeft.
- [Bereik]: valideert of de eigenschapswaarde binnen een opgegeven bereik valt.
- [RegularExpression]: valideert of de eigenschapswaarde overeenkomt met een opgegeven reguliere expressie.
-
[Vereist]: valideert dat het veld niet null is. Zie
[Required]
het kenmerk voor meer informatie over het gedrag van dit kenmerk. - [StringLength]: hiermee wordt gevalideerd dat een waarde van een tekenreekseigenschap geen opgegeven lengtelimiet overschrijdt.
- [Url]: valideert of de eigenschap een URL-indeling heeft.
-
[Extern]: valideert invoer op de client door een actiemethode op de server aan te roepen. Zie
[Remote]
het kenmerk voor meer informatie over het gedrag van dit kenmerk.
Een volledige lijst met validatiekenmerken vindt u in de System.ComponentModel.DataAnnotations naamruimte.
Error messages
Met validatiekenmerken kunt u het foutbericht opgeven dat moet worden weergegeven voor ongeldige invoer. For example:
[StringLength(8, ErrorMessage = "Name length can't be more than 8.")]
Intern worden de kenmerken aangeroepen String.Format met een tijdelijke aanduiding voor de veldnaam en soms aanvullende tijdelijke aanduidingen. For example:
[StringLength(8, ErrorMessage = "{0} length must be between {2} and {1}.", MinimumLength = 6)]
Wanneer het wordt toegepast op een Name
eigenschap, is het foutbericht dat door de voorgaande code is gemaakt, de naamlengte moet tussen 6 en 8 zijn.
Als u wilt zien aan welke parameters worden doorgegeven String.Format
voor het foutbericht van een bepaald kenmerk, raadpleegt u de broncode van DataAnnotations.
Niet-nullable verwijzingstypen en kenmerk [Vereist]
Het validatiesysteem behandelt niet-nullable parameters of afhankelijke eigenschappen alsof ze een [Required(AllowEmptyStrings = true)]
kenmerk hebben. Door contexten in te schakelenNullable
, begint MVC impliciet met het valideren van niet-nullable eigenschappen of parameters alsof ze zijn toegeschreven aan het [Required(AllowEmptyStrings = true)]
kenmerk. Houd rekening met de volgende code:
public class Person
{
public string Name { get; set; }
}
Als de app is gemaakt met <Nullable>enable</Nullable>
, resulteert een ontbrekende waarde Name
in een JSON- of formulierbericht in een validatiefout. Gebruik een verwijzingstype dat null kan worden gebruikt om null- of ontbrekende waarden op te geven voor de Name
eigenschap:
public class Person
{
public string? Name { get; set; }
}
Dit gedrag kan worden uitgeschakeld door het volgende te SuppressImplicitRequiredAttributeForNonNullableReferenceTypes configureren:Startup.ConfigureServices
services.AddControllers(options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true);
[Vereist] validatie op de server
Op de server wordt een vereiste waarde als ontbrekend beschouwd als de eigenschap null is. Een niet-nullable veld is altijd geldig en het foutbericht van het [Required]
kenmerk wordt nooit weergegeven.
Modelbinding voor een niet-nullable eigenschap kan echter mislukken, wat resulteert in een foutbericht zoals The value '' is invalid
. Als u een aangepast foutbericht wilt opgeven voor validatie aan de serverzijde van niet-nullable typen, hebt u de volgende opties:
Het veld null maken (bijvoorbeeld
decimal?
in plaats vandecimal
). Null-waarde<T-waardetypen> worden behandeld als standaard null-typen.Geef het standaardfoutbericht op dat moet worden gebruikt door modelbinding, zoals wordt weergegeven in het volgende voorbeeld:
services.AddRazorPages() .AddMvcOptions(options => { options.MaxModelValidationErrors = 50; options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor( _ => "The field is required."); }); services.AddSingleton<IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
Zie voor meer informatie over modelbindingsfouten waarvoor u standaardberichten DefaultModelBindingMessageProviderkunt instellen.
[Vereist] validatie op de client
Niet-nullable typen en tekenreeksen worden anders verwerkt op de client in vergelijking met de server. Op de client:
- Een waarde wordt alleen als aanwezig beschouwd als er invoer voor wordt ingevoerd. Validatie aan de clientzijde verwerkt daarom niet-null-typen die hetzelfde zijn als null-typen.
- Witruimte in een tekenreeksveld wordt beschouwd als geldige invoer door de vereiste methode jQuery-validatie. Validatie aan de serverzijde beschouwt een vereist tekenreeksveld ongeldig als er alleen witruimte wordt ingevoerd.
Zoals eerder vermeld, worden niet-null-typen behandeld alsof ze een [Required(AllowEmptyStrings = true)]
kenmerk hadden. Dat betekent dat u validatie aan de clientzijde krijgt, zelfs als u het [Required(AllowEmptyStrings = true)]
kenmerk niet toepast. Maar als u het kenmerk niet gebruikt, krijgt u een standaardfoutbericht. Als u een aangepast foutbericht wilt opgeven, gebruikt u het kenmerk.
[Remote] attribute
Het kenmerk [Remote] implementeert validatie aan de clientzijde waarvoor een methode op de server moet worden aangeroepen om te bepalen of veldinvoer geldig is. De app moet bijvoorbeeld controleren of een gebruikersnaam al in gebruik is.
Externe validatie implementeren:
Maak een actiemethode om JavaScript aan te roepen. De externe methode jQuery Validation verwacht een JSON-antwoord:
-
true
betekent dat de invoergegevens geldig zijn. -
false
,undefined
ofnull
betekent dat de invoer ongeldig is. Het standaardfoutbericht weergeven. - Elke andere tekenreeks betekent dat de invoer ongeldig is. De tekenreeks weergeven als een aangepast foutbericht.
Hier volgt een voorbeeld van een actiemethode die een aangepast foutbericht retourneert:
[AcceptVerbs("GET", "POST")] public IActionResult VerifyEmail(string email) { if (!_userService.VerifyEmail(email)) { return Json($"Email {email} is already in use."); } return Json(true); }
-
Maak in de modelklasse aantekeningen op de eigenschap met een
[Remote]
kenmerk dat verwijst naar de validatieactiemethode, zoals wordt weergegeven in het volgende voorbeeld:[Remote(action: "VerifyEmail", controller: "Users")] public string Email { get; set; }
Additional fields
Met AdditionalFields de eigenschap van het [Remote]
kenmerk kunt u combinaties van velden valideren op basis van gegevens op de server. Als het User
model bijvoorbeeld eigenschappen had en LastName
eigenschappen hadFirstName
, wilt u mogelijk controleren of bestaande gebruikers die twee namen al hebben. In het volgende voorbeeld ziet u hoe u AdditionalFields
gebruikt:
[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
kan expliciet worden ingesteld op de tekenreeksen FirstName en LastName, maar het gebruik van de operator nameof vereenvoudigt later herstructureren. De actiemethode voor deze validatie moet beide firstName
en lastName
argumenten accepteren:
[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);
}
Wanneer de gebruiker een voor- of achternaam invoert, voert JavaScript een externe aanroep uit om te zien of dat paar namen is gebruikt.
Als u twee of meer extra velden wilt valideren, geeft u deze op als een door komma's gescheiden lijst. Als u bijvoorbeeld een MiddleName
eigenschap wilt toevoegen aan het model, stelt u het [Remote]
kenmerk in zoals wordt weergegeven in het volgende voorbeeld:
[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(FirstName) + "," + nameof(LastName))]
public string MiddleName { get; set; }
AdditionalFields
, net als alle kenmerkargumenten, moet een constante expressie zijn. Gebruik daarom geen geïnterpoleerde tekenreeks of aanroep Join om te initialiseren AdditionalFields
.
Alternatieven voor ingebouwde kenmerken
Als u validatie niet hebt opgegeven door ingebouwde kenmerken, kunt u het volgende doen:
Custom attributes
Voor scenario's die de ingebouwde validatiekenmerken niet verwerken, kunt u aangepaste validatiekenmerken maken. Maak een klasse die de ValidationAttributemethode overschrijft en overschrijft IsValid .
De IsValid
methode accepteert een object met de naamwaarde. Dit is de invoer die moet worden gevalideerd. Een overbelasting accepteert ook een ValidationContext object, dat aanvullende informatie biedt, zoals het modelexemplaren dat is gemaakt door modelbinding.
In het volgende voorbeeld wordt gecontroleerd of de releasedatum voor een film in het klassieke genre niet later is dan een bepaald jaar. Het [ClassicMovie]
kenmerk:
- Wordt alleen uitgevoerd op de server.
- Voor klassieke films valideert u de releasedatum:
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;
}
}
De movie
variabele in het voorgaande voorbeeld vertegenwoordigt een Movie
object dat de gegevens van de inzending van het formulier bevat. Wanneer de validatie mislukt, wordt een ValidationResult foutbericht geretourneerd.
IValidatableObject
Het voorgaande voorbeeld werkt alleen met Movie
typen. Een andere optie voor validatie op klasseniveau is om te implementeren IValidatableObject in de modelklasse, zoals wordt weergegeven in het volgende voorbeeld:
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) });
}
}
}
Knooppuntvalidatie op het hoogste niveau
Knooppunten op het hoogste niveau zijn onder andere:
- Action parameters
- Controller properties
- Parameters voor pagina-handler
- Eigenschappen van paginamodel
Modelgebonden knooppunten op het hoogste niveau worden gevalideerd naast het valideren van modeleigenschappen. In het volgende voorbeeld van de voorbeeld-app gebruikt de VerifyPhone
methode om RegularExpressionAttribute de phone
actieparameter te valideren:
[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);
}
Knooppunten op het hoogste niveau kunnen worden gebruikt BindRequiredAttribute met validatiekenmerken. In het volgende voorbeeld uit de voorbeeld-app geeft de CheckAge
methode aan dat de age
parameter moet worden gebonden aan de querytekenreeks wanneer het formulier wordt verzonden:
[HttpPost]
public IActionResult CheckAge([BindRequired, FromQuery] int age)
{
Op de pagina Leeftijd controleren (CheckAge.cshtml
) zijn er twee formulieren. Het eerste formulier verzendt een Age
waarde van 99
als een querytekenreeksparameter: https://localhost:5001/Users/CheckAge?Age=99
.
Wanneer een correct opgemaakte age
parameter uit de querytekenreeks wordt verzonden, wordt het formulier gevalideerd.
Het tweede formulier op de pagina Leeftijd controleren verzendt de Age
waarde in de hoofdtekst van de aanvraag en de validatie mislukt. Binding mislukt omdat de age
parameter afkomstig moet zijn van een queryreeks.
Maximum errors
Validatie stopt wanneer het maximum aantal fouten is bereikt (standaard 200). U kunt dit nummer configureren met de volgende code in Startup.ConfigureServices
:
services.AddRazorPages()
.AddMvcOptions(options =>
{
options.MaxModelValidationErrors = 50;
options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
_ => "The field is required.");
});
services.AddSingleton<IValidationAttributeAdapterProvider,
CustomValidationAttributeAdapterProvider>();
Maximum recursion
ValidationVisitor doorkruist de objectgrafiek van het model dat wordt gevalideerd. Voor modellen die diep zijn of oneindig recursief zijn, kan validatie leiden tot stackoverloop.
MvcOptions.MaxValidationDepth biedt een manier om validatie vroeg te stoppen als de bezoeker een geconfigureerde diepte overschrijdt. De standaardwaarde is MvcOptions.MaxValidationDepth
32.
Automatic short-circuit
Validatie wordt automatisch kortsluiting (overgeslagen) als de modelgrafiek geen validatie vereist. Objecten waarvoor de runtime validatie overslaat voor verzamelingen primitieven (zoals byte[]
, string[]
, Dictionary<string, string>
) en complexe objectgrafieken die geen geldige gegevens bevatten.
Client-side validation
Validatie aan de clientzijde voorkomt verzending totdat het formulier geldig is. Met de knop Verzenden wordt JavaScript uitgevoerd waarmee het formulier wordt verzonden of foutberichten worden weergegeven.
Validatie aan de clientzijde voorkomt een onnodige retour naar de server wanneer er invoerfouten zijn op een formulier. De volgende scriptverwijzingen in validatie _Layout.cshtml
aan de clientzijde en _ValidationScriptsPartial.cshtml
ondersteunen deze:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.js"></script>
Het jQuery Unobtrusive Validation-script is een aangepaste Microsoft front-endbibliotheek die voortbouwt op de populaire jQuery Validation-invoegtoepassing . Zonder jQuery Unobtrusive Validation moet u dezelfde validatielogica op twee plaatsen codeeren: eenmaal in de validatiekenmerken aan de serverzijde van modeleigenschappen en vervolgens opnieuw in scripts aan de clientzijde.
Tag Helpers en HTML-helpers gebruiken in plaats daarvan de validatiekenmerken en typ metagegevens van modeleigenschappen om HTML 5-kenmerken data-
weer te geven voor de formulierelementen die moeten worden gevalideerd. jQuery Unobtrusive Validation parseert de data-
kenmerken en geeft de logica door aan jQuery Validation, waardoor de validatielogica aan de serverzijde wordt gekopieerd naar de client. U kunt validatiefouten op de client weergeven met behulp van taghelpers, zoals hier wordt weergegeven:
<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>
De voorgaande tag-helpers geven de volgende HTML weer:
<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>
U ziet dat de data-
kenmerken in de HTML-uitvoer overeenkomen met de validatiekenmerken voor de Movie.ReleaseDate
eigenschap. Het data-val-required
kenmerk bevat een foutbericht dat moet worden weergegeven als de gebruiker het veld releasedatum niet invult. jQuery Unobtrusive Validation geeft deze waarde door aan de methode jQuery Validation required(), die dat bericht vervolgens weergeeft in het bijbehorende <spanelement> .
Validatie van gegevenstypen is gebaseerd op het .NET-type van een eigenschap, tenzij dat wordt overschreven door een [DataType] -kenmerk. Browsers hebben hun eigen standaardfoutberichten, maar het jQuery Validation Unobtrusive Validation Package kan deze berichten overschrijven.
[DataType]
met kenmerken en subklassen zoals [EmailAddress] kunt u het foutbericht opgeven.
Unobtrusive validation
Zie dit GitHub-probleem voor informatie over onopvallende validatie.
Validatie toevoegen aan dynamische formulieren
jQuery Unobtrusive Validation geeft validatielogica en parameters door aan jQuery-validatie wanneer de pagina voor het eerst wordt geladen. Validatie werkt daarom niet automatisch voor dynamisch gegenereerde formulieren. Als u validatie wilt inschakelen, vertelt u jQuery Unobtrusive Validation om het dynamische formulier direct te parseren nadat u het hebt gemaakt. Met de volgende code wordt bijvoorbeeld validatie aan de clientzijde ingesteld op een formulier dat via AJAX is toegevoegd.
$.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);
}
})
De $.validator.unobtrusive.parse()
methode accepteert een jQuery-selector voor het ene argument. Deze methode vertelt jQuery Unobtrusive Validation om de data-
kenmerken van formulieren in die selector te parseren. De waarden van deze kenmerken worden vervolgens doorgegeven aan de jQuery Validation-invoegtoepassing.
Validatie toevoegen aan dynamische besturingselementen
De $.validator.unobtrusive.parse()
methode werkt op een heel formulier, niet op afzonderlijke dynamisch gegenereerde besturingselementen, zoals <input>
en <select/>
. Als u het formulier opnieuw wilt parseren, verwijdert u de validatiegegevens die zijn toegevoegd toen het formulier eerder werd geparseerd, zoals wordt weergegeven in het volgende voorbeeld:
$.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);
}
})
Validatie aan de clientzijde
Aangepaste validatie aan de clientzijde wordt uitgevoerd door HTML-kenmerken te genereren data-
die werken met een aangepaste jQuery-validatieadapter. De volgende voorbeeldadaptercode is geschreven voor de [ClassicMovie]
kenmerken die [ClassicMovieWithClientValidator]
eerder in dit artikel zijn geïntroduceerd:
$.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;
});
Zie de documentatie voor jQuery-validatie voor informatie over het schrijven van adapters.
Het gebruik van een adapter voor een bepaald veld wordt geactiveerd door data-
kenmerken die:
- Markeer het veld als onderworpen aan validatie (
data-val="true"
). - Identificeer de naam van een validatieregel en de tekst van het foutbericht (bijvoorbeeld
data-val-rulename="Error message."
). - Geef eventuele aanvullende parameters op die de validator nodig heeft (bijvoorbeeld
data-val-rulename-param1="value"
).
In het volgende voorbeeld ziet u de data-
kenmerken voor het kenmerk van ClassicMovie
de voorbeeld-app:
<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="">
Zoals eerder vermeld, gebruiken Tag Helpers en HTML-helpers informatie uit validatiekenmerken om kenmerken weer te geven data-
. Er zijn twee opties voor het schrijven van code die resulteert in het maken van aangepaste data-
HTML-kenmerken:
- Maak een klasse die is afgeleid van AttributeAdapterBase<TAttribute> en een klasse die implementeert IValidationAttributeAdapterProvider, en registreer uw kenmerk en de bijbehorende adapter in DI. Deze methode volgt het principe van één verantwoordelijkheid in dat servergerelateerde en clientgerelateerde validatiecode zich in afzonderlijke klassen bevindt. De adapter heeft ook het voordeel dat omdat deze is geregistreerd in DI, andere services in DI beschikbaar zijn indien nodig.
- Implementeren IClientModelValidator in uw ValidationAttribute klas. Deze methode is mogelijk geschikt als het kenmerk geen validatie aan de serverzijde uitvoert en geen services van DI nodig heeft.
AttributeAdapter voor validatie aan clientzijde
Deze methode voor het weergeven data-
van kenmerken in HTML wordt gebruikt door het ClassicMovie
kenmerk in de voorbeeld-app. Clientvalidatie toevoegen met behulp van deze methode:
Maak een kenmerkadapterklasse voor het aangepaste validatiekenmerk. De klasse afleiden van AttributeAdapterBase<TAttribute>. Maak een
AddValidation
methode waarmee kenmerken worden toegevoegddata-
aan de weergegeven uitvoer, zoals wordt weergegeven in dit voorbeeld: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(); }
Maak een adapterproviderklasse die wordt geïmplementeerd IValidationAttributeAdapterProvider. Geef in de GetAttributeAdapter methode het aangepaste kenmerk door aan de constructor van de adapter, zoals wordt weergegeven in dit voorbeeld:
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); } }
Registreer de adapterprovider voor DI in
Startup.ConfigureServices
:services.AddRazorPages() .AddMvcOptions(options => { options.MaxModelValidationErrors = 50; options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor( _ => "The field is required."); }); services.AddSingleton<IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();
IClientModelValidator voor validatie aan clientzijde
Deze methode voor het weergeven data-
van kenmerken in HTML wordt gebruikt door het ClassicMovieWithClientValidator
kenmerk in de voorbeeld-app. Clientvalidatie toevoegen met behulp van deze methode:
Implementeer de IClientModelValidator interface in het aangepaste validatiekenmerk en maak een AddValidation methode. Voeg in de
AddValidation
methode kenmerken toedata-
voor validatie, zoals wordt weergegeven in het volgende voorbeeld: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; } }
Validatie aan clientzijde uitschakelen
Met de volgende code wordt clientvalidatie in Razor Pages uitgeschakeld:
services.AddRazorPages()
.AddViewOptions(options =>
{
options.HtmlHelperOptions.ClientValidationEnabled = false;
});
Andere opties voor het uitschakelen van validatie aan clientzijde:
- Markeer de verwijzing
_ValidationScriptsPartial
in alle.cshtml
bestanden als commentaar. - Verwijder de inhoud van het bestand Pages\Shared_ValidationScriptsPartial.cshtml .
De voorgaande benadering voorkomt geen validatie aan de clientzijde van ASP.NET Core-klassebibliotheek IdentityRazor . Zie Scaffold Identity in ASP.NET Core-projectenvoor meer informatie.