Validation de modèle dans ASP.NET Core MVC et Razor PagesModel validation in ASP.NET Core MVC and Razor Pages

Cet article explique comment valider l’entrée d’utilisateur dans une application ASP.NET Core MVC ou Razor Pages.This article explains how to validate user input in an ASP.NET Core MVC or Razor Pages app.

Affichez ou téléchargez un exemple de code (procédure de téléchargement).View or download sample code (how to download).

État du modèleModel state

L’état du modèle représente les erreurs qui proviennent de deux sous-systèmes : liaison de modèle et validation de modèle.Model state represents errors that come from two subsystems: model binding and model validation. Les erreurs qui proviennent de la liaison de modèle sont généralement des erreurs de conversion de données (par exemple, un « x » est entré dans un champ qui attend un nombre entier).Errors that originate from model binding are generally data conversion errors (for example, an "x" is entered in a field that expects an integer). La validation de modèle se produit après la liaison de modèle, et signale les erreurs où les données ne sont pas conformes aux règles d’entreprise (par exemple, un 0 est entré dans un champ qui attend une évaluation comprise entre 1 et 5).Model validation occurs after model binding and reports errors where the data doesn't conform to business rules (for example, a 0 is entered in a field that expects a rating between 1 and 5).

La liaison et la validation de modèle se produisent avant l’exécution d’une action de contrôleur ou d’une méthode de gestionnaire Razor Pages.Both model binding and validation occur before the execution of a controller action or a Razor Pages handler method. Pour les applications web, il incombe à l’application d’inspecter ModelState.IsValid et de réagir de façon appropriée.For web apps, it's the app's responsibility to inspect ModelState.IsValid and react appropriately. En règle générale, les applications web réaffichent la page avec un message d’erreur :Web apps typically redisplay the page with an error message:

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

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

    return RedirectToPage("./Index");
}

Les contrôleurs d’API web ne sont pas obligés de vérifier ModelState.IsValid s’ils ont l’attribut [ApiController].Web API controllers don't have to check ModelState.IsValid if they have the [ApiController] attribute. Dans ce cas, une réponse HTTP 400 automatique contenant les détails du problème est retournée quand l’état du modèle n’est pas valide.In that case, an automatic HTTP 400 response containing issue details is returned when model state is invalid. Pour plus d’informations, consultez Réponses HTTP 400 automatiques.For more information, see Automatic HTTP 400 responses.

Réexécuter la validationRerun validation

La validation est automatique, mais vous souhaiterez peut-être la répéter manuellement.Validation is automatic, but you might want to repeat it manually. Par exemple, vous pourriez calculer une valeur pour une propriété, et souhaiter réexécuter la validation après avoir affecté la valeur calculée comme valeur de la propriété.For example, you might compute a value for a property and want to rerun validation after setting the property to the computed value. Pour réexécuter la validation, appelez la méthode TryValidateModel, comme indiqué ici :To rerun validation, call the TryValidateModel method, as shown here:

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

TryValidateModel(movie);

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

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

return View(movie);

Attributs de validationValidation attributes

Les attributs de validation vous permettent de spécifier des règles de validation pour des propriétés de modèle.Validation attributes let you specify validation rules for model properties. L’exemple suivant tiré de l’exemple d’application montre une classe de modèle qui est annotée avec des attributs de validation.The following example from the sample app shows a model class that is annotated with validation attributes. L’attribut [ClassicMovie] est un attribut de validation personnalisé, et les autres sont prédéfinis.The [ClassicMovie] attribute is a custom validation attribute and the others are built-in. ([ClassicMovie2] n’est pas affiché ici ; il montre une autre façon d’implémenter un attribut personnalisé.)(Not shown is [ClassicMovie2], which shows an alternative way to implement a custom attribute.)

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

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

    [ClassicMovie(1960)]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

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

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

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

    public bool Preorder { get; set; }
}

Attributs prédéfinisBuilt-in attributes

Voici certains des attributs de validation prédéfinis :Here are some of the built-in validation attributes:

  • [CreditCard]: vérifie que la propriété a un format de carte de crédit.[CreditCard]: Validates that the property has a credit card format.
  • [Compare]: vérifie que deux propriétés d’un modèle correspondent.[Compare]: Validates that two properties in a model match.
  • [EmailAddress]: vérifie que la propriété a un format d’e-mail.[EmailAddress]: Validates that the property has an email format.
  • [Phone]: vérifie que la propriété a un format de numéro de téléphone.[Phone]: Validates that the property has a telephone number format.
  • [Range]: vérifie que la valeur de propriété est comprise dans une plage spécifiée.[Range]: Validates that the property value falls within a specified range.
  • [RegularExpression]: vérifie que la valeur de propriété correspond à une expression régulière spécifiée.[RegularExpression]: Validates that the property value matches a specified regular expression.
  • [Required]: vérifie que le champ n’est pas Null.[Required]: Validates that the field is not null. Pour plus d’informations sur le comportement de cet attribut, consultez Attribut [Required].See [Required] attribute for details about this attribute's behavior.
  • [StringLength]: vérifie qu’une valeur de propriété de chaîne ne dépasse pas une limite de longueur spécifiée.[StringLength]: Validates that a string property value doesn't exceed a specified length limit.
  • [Url]: vérifie que la propriété a un format d’URL.[Url]: Validates that the property has a URL format.
  • [Remote]: valide l’entrée sur le client en appelant une méthode d’action sur le serveur.[Remote]: Validates input on the client by calling an action method on the server. Pour plus d’informations sur le comportement de cet attribut, consultez Attribut [Remote].See [Remote] attribute for details about this attribute's behavior.

Vous trouverez la liste complète des attributs de validation dans l’espace de noms System.ComponentModel.DataAnnotations.A complete list of validation attributes can be found in the System.ComponentModel.DataAnnotations namespace.

Messages d’erreurError messages

Les attributs de validation vous permettent de spécifier le message d’erreur à afficher pour l’entrée non valide.Validation attributes let you specify the error message to be displayed for invalid input. Par exemple :For example:

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

En interne, les attributs appellent String.Format avec un espace réservé pour le nom de champ et parfois d’autres espaces réservés.Internally, the attributes call String.Format with a placeholder for the field name and sometimes additional placeholders. Par exemple :For example:

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

Appliqué à une propriété Name, le message d’erreur créé par le code précédent serait « Name length must be between 6 and 8 ».When applied to a Name property, the error message created by the preceding code would be "Name length must be between 6 and 8.".

Pour savoir quels paramètres sont passés à String.Format pour le message d’erreur d’un attribut particulier, consultez le code source de DataAnnotations.To find out which parameters are passed to String.Format for a particular attribute's error message, see the DataAnnotations source code.

Attribut [Required][Required] attribute

Par défaut, le système de validation traite les propriétés ou paramètres n’acceptant pas les valeurs Null comme s’ils avaient un attribut [Required].By default, the validation system treats non-nullable parameters or properties as if they had a [Required] attribute. Les types valeur comme decimal et int n’acceptent pas les valeurs Null.Value types such as decimal and int are non-nullable.

Validation de [Required] sur le serveur[Required] validation on the server

Sur le serveur, une valeur obligatoire est considérée comme manquante si la propriété est Null.On the server, a required value is considered missing if the property is null. Un champ n’acceptant pas les valeurs Null est toujours valide, et le message d’erreur de l’attribut [Required] n’est jamais affiché.A non-nullable field is always valid, and the [Required] attribute's error message is never displayed.

Toutefois, la liaison de modèle pour une propriété n’acceptant pas les valeurs Null peut échouer, entraînant l’affichage d’un message d’erreur tel que The value '' is invalid.However, model binding for a non-nullable property may fail, resulting in an error message such as The value '' is invalid. Pour spécifier un message d’erreur personnalisé pour la validation côté serveur des types n’acceptant pas les valeurs Null, vous disposez des options suivantes :To specify a custom error message for server-side validation of non-nullable types, you have the following options:

  • Rendre le champ Nullable (par exemple, decimal? au lieu de decimal).Make the field nullable (for example, decimal? instead of decimal). Les types valeur Nullable<T> sont traités comme des types Nullable standard.Nullable<T> value types are treated like standard nullable types.

  • Spécifier le message d’erreur par défaut devant être utilisé par la liaison de modèle, comme indiqué dans l’exemple suivant :Specify the default error message to be used by model binding, as shown in the following example:

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

    Pour plus d’informations sur les erreurs de liaison de modèle pour lesquelles vous pouvez définir des messages par défaut, consultez DefaultModelBindingMessageProvider.For more information about model binding errors that you can set default messages for, see DefaultModelBindingMessageProvider.

Validation de [Required] sur le client[Required] validation on the client

Les chaînes et les types n’acceptant pas les valeurs Null sont gérés différemment sur le client et sur le serveur.Non-nullable types and strings are handled differently on the client compared to the server. Sur le client :On the client:

  • Une valeur est considérée comme présente uniquement si une entrée est tapée pour celle-ci.A value is considered present only if input is entered for it. Par conséquent, la validation côté client gère les types n’acceptant pas les valeurs Null de la même façon que les types NullableTherefore, client-side validation handles non-nullable types the same as nullable types.
  • Un espace blanc dans un champ de chaîne est considéré comme une entrée valide par la méthode required jQuery Validate.Whitespace in a string field is considered valid input by the jQuery Validation required method. La validation côté serveur considère qu’un champ de chaîne obligatoire est non valide si seul un espace blanc est entré.Server-side validation considers a required string field invalid if only whitespace is entered.

Comme indiqué précédemment, les types n’acceptant pas les valeurs Null sont traités comme s’ils avaient un attribut [Required].As noted earlier, non-nullable types are treated as though they had a [Required] attribute. Cela signifie que vous bénéficiez d’une validation côté client même si vous n’appliquez pas l’attribut [Required].That means you get client-side validation even if you don't apply the [Required] attribute. En revanche, si vous n’utilisez pas l’attribut, vous recevez un message d’erreur par défaut.But if you don't use the attribute, you get a default error message. Pour spécifier un message d’erreur personnalisé, utilisez l’attribut.To specify a custom error message, use the attribute.

Attribut [Remote][Remote] attribute

L’attribut [Remote] implémente la validation côté client qui nécessite l’appel d’une méthode sur le serveur pour déterminer si le champ d’entrée est valide.The [Remote] attribute implements client-side validation that requires calling a method on the server to determine whether field input is valid. Par exemple, l’application peut avoir besoin de vérifier si un nom d’utilisateur est déjà en cours d’utilisation.For example, the app may need to verify whether a user name is already in use.

Pour implémenter la validation à distanceTo implement remote validation:

  1. Créez une méthode d’action devant être appelée par JavaScript.Create an action method for JavaScript to call. La méthode remote jQuery Validate attend une réponse JSON :The jQuery Validate remote method expects a JSON response:

    • "true" signifie que les données d’entrée sont valides."true" means the input data is valid.
    • "false", undefined ou null signifie que l’entrée n’est pas valide."false", undefined, or null means the input is invalid. Affichez le message d’erreur par défaut.Display the default error message.
    • Toute autre chaîne signifie que l’entrée n’est pas valide.Any other string means the input is invalid. Affichez la chaîne en tant que message d’erreur personnalisé.Display the string as a custom error message.

    Voici un exemple de méthode d’action qui retourne un message d’erreur personnalisé :Here's an example of an action method that returns a custom error message:

    [AcceptVerbs("Get", "Post")]
    public IActionResult VerifyEmail(string email)
    {
        if (!_userRepository.VerifyEmail(email))
        {
            return Json($"Email {email} is already in use.");
        }
    
        return Json(true);
    }
    
  2. Dans la classe de modèle, annotez la propriété avec un attribut [Remote] qui pointe vers la méthode d’action de validation, comme indiqué dans l’exemple suivant :In the model class, annotate the property with a [Remote] attribute that points to the validation action method, as shown in the following example:

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

    L’attribut [Remote] se trouve dans l’espace de noms Microsoft.AspNetCore.Mvc.The [Remote] attribute is in the Microsoft.AspNetCore.Mvc namespace. Installez le package NuGet Microsoft.AspNetCore.Mvc.ViewFeatures, si vous n’utilisez pas le métapaquet Microsoft.AspNetCore.App ou Microsoft.AspNetCore.All.Install the Microsoft.AspNetCore.Mvc.ViewFeatures NuGet package if you're not using the Microsoft.AspNetCore.App or Microsoft.AspNetCore.All metapackage.

Champs supplémentairesAdditional fields

La propriété AdditionalFields de l’attribut [Remote] vous permet de valider des combinaisons de champs relativement à des données présentes sur le serveur.The AdditionalFields property of the [Remote] attribute lets you validate combinations of fields against data on the server. Par exemple, si le modèle User a des propriétés FirstName et LastName, vous pouvez vérifier qu’aucun utilisateur existant n’a déjà cette paire de noms.For example, if the User model had FirstName and LastName properties, you might want to verify that no existing users already have that pair of names. L'exemple suivant montre comment utiliser AdditionalFields :The following example shows how to use AdditionalFields:

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

AdditionalFields peut être défini explicitement avec les chaînes "FirstName" et "LastName", mais l’utilisation de l’opérateur nameof simplifie la refactorisation ultérieure.AdditionalFields could be set explicitly to the strings "FirstName" and "LastName", but using the nameof operator simplifies later refactoring. La méthode d’action pour cette validation doit accepter les arguments de nom et de prénom :The action method for this validation must accept both first name and last name arguments:

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

    return Json(data: true);
}

Quand l’utilisateur entre un nom ou un prénom, JavaScript effectue un appel à distance pour vérifier si cette paire de noms est déjà utilisée.When the user enters a first or last name, JavaScript makes a remote call to see if that pair of names has been taken.

Pour valider deux champs supplémentaires ou plus, spécifiez-les sous la forme d’une liste délimitée par des virgules.To validate two or more additional fields, provide them as a comma-delimited list. Par exemple, pour ajouter une propriété MiddleName au modèle, définissez l’attribut [Remote] comme indiqué dans l’exemple suivant :For example, to add a MiddleName property to the model, set the [Remote] attribute as shown in the following example:

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

AdditionalFields, comme tous les arguments d’attribut, doit être une expression constante.AdditionalFields, like all attribute arguments, must be a constant expression. Vous ne devez donc pas utiliser une chaîne interpolée ou appeler Join pour initialiser AdditionalFields.Therefore, don't use an interpolated string or call Join to initialize AdditionalFields.

Alternatives aux attributs prédéfinisAlternatives to built-in attributes

Si vous avez besoin d’une validation non fournie par les attributs prédéfinis, vous pouvez :If you need validation not provided by built-in attributes, you can:

Attributs personnalisésCustom attributes

Pour les scénarios non gérés par les attributs de validation prédéfinis, vous pouvez créer des attributs de validation personnalisés.For scenarios that the built-in validation attributes don't handle, you can create custom validation attributes. Créez une classe qui hérite de ValidationAttribute et substituez la méthode IsValid.Create a class that inherits from ValidationAttribute, and override the IsValid method.

La méthode IsValid accepte un objet nommé value, qui est l’entrée à valider.The IsValid method accepts an object named value, which is the input to be validated. Une surcharge accepte également un objet ValidationContext, qui fournit des informations supplémentaires telles que l’instance de modèle créée par la liaison de modèle.An overload also accepts a ValidationContext object, which provides additional information, such as the model instance created by model binding.

L’exemple suivant vérifie que la date de sortie d’un film appartenant au genre Classic n’est pas ultérieure à une année spécifiée.The following example validates that the release date for a movie in the Classic genre isn't later than a specified year. L’attribut [ClassicMovie2] vérifie d’abord le genre, et continue uniquement s’il s’agit de Classic.The [ClassicMovie2] attribute checks the genre first and continues only if it's Classic. Pour les films identifiés comme des classiques, il vérifie si la date de sortie n’est pas ultérieure à la limite passée au constructeur d’attribut.For movies identified as classics, it checks the release date to make sure it's not later than the limit passed to the attribute constructor.)

public class ClassicMovieAttribute : ValidationAttribute
{
    private int _year;

    public ClassicMovieAttribute(int year)
    {
        _year = year;
    }

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

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

        return ValidationResult.Success;
    }

    public int Year => _year;

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

La variable movie de l’exemple précédent représente un objet Movie qui contient les données de l’envoi du formulaire.The movie variable in the preceding example represents a Movie object that contains the data from the form submission. La méthode IsValid vérifie la date et le genre.The IsValid method checks the date and genre. Si la validation réussit, IsValid retourne un code ValidationResult.Success.Upon successful validation, IsValid returns a ValidationResult.Success code. Quand la validation échoue, un ValidationResult avec un message d’erreur est retourné.When validation fails, a ValidationResult with an error message is returned.

IValidatableObjectIValidatableObject

L’exemple précédent fonctionne uniquement avec les types Movie.The preceding example works only with Movie types. Une autre option de validation au niveau de la classe consiste à implémenter IValidatableObject dans la classe de modèle, comme indiqué dans l’exemple suivant :Another option for class-level validation is to implement IValidatableObject in the model class, as shown in the following example:

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

    public int Id { get; set; }

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

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

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

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

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

    public bool Preorder { get; set; }

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

Validation du nœud de niveau supérieurTop-level node validation

Les nœuds de niveau supérieur incluent les éléments suivants :Top-level nodes include:

  • Paramètres d’actionAction parameters
  • Propriétés du contrôleurController properties
  • Paramètres du gestionnaire de pagePage handler parameters
  • Propriétés du modèle de pagePage model properties

Les nœuds de niveau supérieur liés au modèle sont validés en plus de la validation des propriétés du modèle.Model-bound top-level nodes are validated in addition to validating model properties. Dans l’exemple suivant tiré de l’exemple d’application, la méthode VerifyPhone utilise RegularExpressionAttribute pour valider le paramètre d’action phone :In the following example from the sample app, the VerifyPhone method uses the RegularExpressionAttribute to validate the phone action parameter:

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

Les nœuds de niveau supérieur peuvent utiliser BindRequiredAttribute avec des attributs de validation.Top-level nodes can use BindRequiredAttribute with validation attributes. Dans l’exemple suivant de l’exemple d’application, la méthode CheckAge spécifie que le paramètre age doit être lié à partir de la chaîne de requête au moment de l’envoi du formulaire :In the following example from the sample app, the CheckAge method specifies that the age parameter must be bound from the query string when the form is submitted:

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

Dans la page de vérification de l’âge (CheckAge.cshtml), il existe deux formulaires.In the Check Age page (CheckAge.cshtml), there are two forms. Le premier formulaire envoie une valeur Age égale à 99 en tant que chaîne de requête : https://localhost:5001/Users/CheckAge?Age=99.The first form submits an Age value of 99 as a query string: https://localhost:5001/Users/CheckAge?Age=99.

Quand un paramètre age au format approprié est envoyé à partir de la chaîne de requête, le formulaire est validé.When a properly formatted age parameter from the query string is submitted, the form validates.

Le second formulaire de la page de vérification de l’âge envoie la valeur Age dans le corps de la requête, ce qui entraîne un échec de la validation.The second form on the Check Age page submits the Age value in the body of the request, and validation fails. L’échec de la liaison est dû au fait que le paramètre age doit provenir d’une chaîne de requête.Binding fails because the age parameter must come from a query string.

Lors de l’exécution avec CompatibilityVersion.Version_2_1 ou version ultérieure, la validation du nœud de niveau supérieur est activée par défaut.When running with CompatibilityVersion.Version_2_1 or later, top-level node validation is enabled by default. Autrement, la validation du nœud de niveau supérieur est désactivée.Otherwise, top-level node validation is disabled. L’option par défaut peut être remplacée en définissant la propriété AllowValidatingTopLevelNodes dans (Startup.ConfigureServices), comme illustré ici :The default option can be overridden by setting the AllowValidatingTopLevelNodes property in (Startup.ConfigureServices), as shown here:

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

Quantité maximale d’erreursMaximum errors

La validation s’arrête quand le nombre maximal d’erreurs est atteint (200 par défaut).Validation stops when the maximum number of errors is reached (200 by default). Vous pouvez configurer ce nombre avec le code suivant dans Startup.ConfigureServices :You can configure this number with the following code in Startup.ConfigureServices:

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

Récursivité maximaleMaximum recursion

ValidationVisitor parcourt le graphe d’objet du modèle en cours de validation.ValidationVisitor traverses the object graph of the model being validated. Pour les modèles très profonds ou infiniment récursifs, la validation peut entraîner un dépassement de la capacité de la pile.For models that are very deep or are infinitely recursive, validation may result in stack overflow. MvcOptions.MaxValidationDepth fournit un moyen d’interrompre la validation de manière anticipée si la récursivité du visiteur dépasse une profondeur configurée.MvcOptions.MaxValidationDepth provides a way to stop validation early if the visitor recursion exceeds a configured depth. La valeur par défaut de MvcOptions.MaxValidationDepth est 200 lors de l’exécution avec CompatibilityVersion.Version_2_2 ou ultérieure.The default value of MvcOptions.MaxValidationDepth is 200 when running with CompatibilityVersion.Version_2_2 or later. Pour les versions antérieures, la valeur est Null, ce qui signifie qu’il n’y a aucune contrainte de profondeur.For earlier versions, the value is null, which means no depth constraint.

Court-circuit automatiqueAutomatic short-circuit

La validation est automatiquement court-circuitée (ignorée) si le graphe du modèle ne nécessite pas de validation.Validation is automatically short-circuited (skipped) if the model graph doesn't require validation. Les objets pour lesquels le runtime ignore la validation comprennent les collections de primitives (telles que byte[], string[], Dictionary<string, string>) et les graphes d’objets complexes qui n’ont pas de validateur.Objects that the runtime skips validation for include collections of primitives (such as byte[], string[], Dictionary<string, string>) and complex object graphs that don't have any validators.

Désactiver la validationDisable validation

Pour désactiver la validationTo disable validation:

  1. Créez une implémentation de IObjectModelValidator qui ne marque aucun champ comme étant non valide.Create an implementation of IObjectModelValidator that doesn't mark any fields as invalid.

    public class NullObjectModelValidator : IObjectModelValidator
    {
        public void Validate(
            ActionContext actionContext,
            ValidationStateDictionary validationState,
            string prefix,
            object model)
        {
        }
    }
    
  2. Ajoutez le code suivant à Startup.ConfigureServices pour remplacer l’implémentation par défaut de IObjectModelValidator dans le conteneur d’injection de dépendances.Add the following code to Startup.ConfigureServices to replace the default IObjectModelValidator implementation in the dependency injection container.

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

Vous risquez toujours de voir des erreurs d’état du modèle provenant de la liaison de modèle.You might still see model state errors that originate from model binding.

Validation côté clientClient-side validation

La validation côté client empêche l’envoi jusqu’à ce que le formulaire soit valide.Client-side validation prevents submission until the form is valid. Le bouton Submit exécute le code JavaScript qui envoie le formulaire ou qui affiche des messages d’erreur.The Submit button runs JavaScript that either submits the form or displays error messages.

La validation côté client permet d’éviter un aller-retour inutile vers le serveur quand il existe des erreurs d’entrée sur un formulaire.Client-side validation avoids an unnecessary round trip to the server when there are input errors on a form. Les références de script suivantes dans _Layout.cshtml et _ValidationScriptsPartial.cshtml prennent en charge la validation côté client :The following script references in _Layout.cshtml and _ValidationScriptsPartial.cshtml support client-side validation:

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

Le script jQuery Unobtrusive Validation est une bibliothèque frontale personnalisée de Microsoft qui s’appuie sur le plug-in bien connu jQuery Validate.The jQuery Unobtrusive Validation script is a custom Microsoft front-end library that builds on the popular jQuery Validate plugin. Sans jQuery Unobtrusive Validation, vous devriez coder la même logique de validation à deux endroits : une fois dans les attributs de validation côté serveur sur les propriétés du modèle, puis à nouveau dans les scripts côté client.Without jQuery Unobtrusive Validation, you would have to code the same validation logic in two places: once in the server-side validation attributes on model properties, and then again in client-side scripts. Au lieu de cela, les Tag Helpers et les helpers HTML utilisent les attributs de validation et les métadonnées de type des propriétés du modèle afin de restituer les attributs data- HTML 5 pour les éléments de formulaire nécessitant une validation.Instead, Tag Helpers and HTML helpers use the validation attributes and type metadata from model properties to render HTML 5 data- attributes for the form elements that need validation. jQuery Unobtrusive Validation analyse les attributs data- et passe la logique à jQuery Validate, en « copiant » la logique de validation côté serveur vers le client.jQuery Unobtrusive Validation parses the data- attributes and passes the logic to jQuery Validate, effectively "copying" the server-side validation logic to the client. Vous pouvez afficher les erreurs de validation sur le client en utilisant des Tag Helpers, comme indiqué ici :You can display validation errors on the client using tag helpers as shown here:

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

Les Tag Helpers précédents restituent le code HTML suivant.The preceding tag helpers render the following HTML.

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

Notez que les attributs data- dans la sortie HTML correspondent aux attributs de validation pour la propriété ReleaseDate.Notice that the data- attributes in the HTML output correspond to the validation attributes for the ReleaseDate property. L’attribut data-val-required contient un message d’erreur à afficher si l’utilisateur ne renseigne pas le champ correspondant à la date de sortie.The data-val-required attribute contains an error message to display if the user doesn't fill in the release date field. jQuery Unobtrusive Validation passe cette valeur à la méthode required() de jQuery Validate, qui affiche alors ce message dans l’élément <span> qui l’accompagne.jQuery Unobtrusive Validation passes this value to the jQuery Validate required() method, which then displays that message in the accompanying <span> element.

La validation du type de données est basée sur le type .NET d’une propriété, sauf en cas de substitution par un attribut [DataType].Data type validation is based on the .NET type of a property, unless that is overridden by a [DataType] attribute. Les navigateurs ont leurs propres messages d’erreur par défaut, mais le package jQuery Validation Unobtrusive Validation peut remplacer ces messages.Browsers have their own default error messages, but the jQuery Validation Unobtrusive Validation package can override those messages. Les attributs [DataType] et les sous-classes comme [EmailAddress] vous permettent de spécifier le message d’erreur.[DataType] attributes and subclasses such as [EmailAddress] let you specify the error message.

Ajouter une validation à des formulaires dynamiquesAdd Validation to Dynamic Forms

jQuery Unobtrusive Validation passe la logique et les paramètres de validation à jQuery Validate lors du premier chargement de la page.jQuery Unobtrusive Validation passes validation logic and parameters to jQuery Validate when the page first loads. Par conséquent, la validation ne fonctionne pas automatiquement sur les formulaires générés de manière dynamique.Therefore, validation doesn't work automatically on dynamically generated forms. Pour activer la validation, vous devez faire en sorte que jQuery Validate analyse le formulaire dynamique immédiatement après l’avoir créé.To enable validation, tell jQuery Unobtrusive Validation to parse the dynamic form immediately after you create it. Par exemple, le code suivant définit la validation côté client sur un formulaire ajouté par le biais d’AJAX.For example, the following code sets up client-side validation on a form added via AJAX.

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

La méthode $.validator.unobtrusive.parse() accepte un sélecteur jQuery comme argument.The $.validator.unobtrusive.parse() method accepts a jQuery selector for its one argument. Cette méthode indique à jQuery Unobtrusive Validation d’analyser les attributs data- des formulaires dans ce sélecteur.This method tells jQuery Unobtrusive Validation to parse the data- attributes of forms within that selector. Les valeurs de ces attributs sont ensuite passées au plug-in jQuery Validate.The values of those attributes are then passed to the jQuery Validate plugin.

Ajouter une validation à des contrôles dynamiquesAdd Validation to Dynamic Controls

La méthode $.validator.unobtrusive.parse() opère sur un formulaire entier, et non sur des contrôles individuels générés de manière dynamique tels que <input> et <select/>.The $.validator.unobtrusive.parse() method works on an entire form, not on individual dynamically generated controls, such as <input> and <select/>. Pour réanalyser le formulaire, supprimez les données de validation qui ont été ajoutées quand le formulaire a été analysé précédemment, comme illustré dans l’exemple suivant :To reparse the form, remove the validation data that was added when the form was parsed earlier, as shown in the following example:

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

Validation personnalisée côté clientCustom client-side validation

La validation personnalisée côté client s’effectue en générant des attributs HTML data- qui fonctionnent avec un adaptateur jQuery Validate personnalisé.Custom client-side validation is done by generating data- HTML attributes that work with a custom jQuery Validate adapter. L’exemple de code d’adaptateur suivant a été écrit pour les attributs ClassicMovie et ClassicMovie2 qui ont été introduits plus haut dans cet article :The following sample adapter code was written for the ClassicMovie and ClassicMovie2 attributes that were introduced earlier in this article:

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

        return true;
    });

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

Pour plus d’informations sur la façon d’écrire des adaptateurs, consultez la documentation de jQuery Validate.For information about how to write adapters, see the jQuery Validate documentation.

L’utilisation d’un adaptateur pour un champ donné est déclenchée par des attributs data- qui :The use of an adapter for a given field is triggered by data- attributes that:

  • Marquent le champ comme étant soumis à validation (data-val="true").Flag the field as being subject to validation (data-val="true").
  • Identifient un nom de règle de validation et un texte de message d’erreur (par exemple, data-val-rulename="Error message.").Identify a validation rule name and error message text (for example, data-val-rulename="Error message.").
  • Fournissent les éventuels paramètres supplémentaires dont le validateur a besoin (par exemple, data-val-rulename-parm1="value").Provide any additional parameters the validator needs (for example, data-val-rulename-parm1="value").

L’exemple suivant montre les attributs data- pour l’attribut ClassicMovie de l’exemple d’application :The following example shows the data- attributes for the sample app's ClassicMovie attribute:

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

Comme mentionné plus haut, les Tag Helpers et les helpers HTML utilisent les informations des attributs de validation pour restituer les attributs data-.As noted earlier, Tag Helpers and HTML helpers use information from validation attributes to render data- attributes. Il existe deux options pour l’écriture de code qui entraîne la création d’attributs HTML data- personnalisés :There are two options for writing code that results in the creation of custom data- HTML attributes:

  • Créez une classe qui dérive de AttributeAdapterBase<TAttribute> et une classe qui implémente IValidationAttributeAdapterProvider, et inscrivez votre attribut et son adaptateur dans l’injection de dépendances.Create a class that derives from AttributeAdapterBase<TAttribute> and a class that implements IValidationAttributeAdapterProvider, and register your attribute and its adapter in DI. Cette méthode respecte le principe de responsabilité unique, dans la mesure où le code de validation lié au serveur et celui lié au client se trouvent dans des classes distinctes.This method follows the single responsibility principal in that server-related and client-related validation code is in separate classes. Il existe un autre avantage : l’adaptateur étant inscrit dans l’injection de dépendances, les autres services dans l’injection de dépendances lui sont accessibles si nécessaire.The adapter also has the advantage that since it is registered in DI, other services in DI are available to it if needed.
  • Implémentez IClientModelValidator dans votre classe ValidationAttribute.Implement IClientModelValidator in your ValidationAttribute class. Cette méthode peut être appropriée si l’attribut n’effectue aucune validation côté serveur et n’a besoin d’aucun service à partir de l’injection de dépendances.This method might be appropriate if the attribute doesn't do any server-side validation and doesn't need any services from DI.

AttributeAdapter pour la validation côté clientAttributeAdapter for client-side validation

Cette méthode de rendu des attributs data- en HTML est utilisée par l’attribut ClassicMovie dans l’exemple d’application.This method of rendering data- attributes in HTML is used by the ClassicMovie attribute in the sample app. Pour ajouter la validation côté client à l’aide de cette méthodeTo add client validation by using this method:

  1. Créez une classe d’adaptateurs d’attributs pour l’attribut de validation personnalisé.Create an attribute adapter class for the custom validation attribute. Dérivez la classe de AttributeAdapterBase<T>.Derive the class from AttributeAdapterBase<T>. Créez une méthode AddValidation qui ajoute des attributs data- à la sortie restituée, comme illustré dans cet exemple :Create an AddValidation method that adds data- attributes to the rendered output, as shown in this example:

    public class ClassicMovieAttributeAdapter : AttributeAdapterBase<ClassicMovieAttribute>
    {
        private int _year;
    
        public ClassicMovieAttributeAdapter(ClassicMovieAttribute attribute, IStringLocalizer stringLocalizer) : base (attribute, stringLocalizer)
        {
            _year = attribute.Year;
        }
        public override void AddValidation(ClientModelValidationContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
    
            MergeAttribute(context.Attributes, "data-val", "true");
            MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage(context));
    
            var year = Attribute.Year.ToString(CultureInfo.InvariantCulture);
            MergeAttribute(context.Attributes, "data-val-classicmovie-year", year);
        }
        public override string GetErrorMessage(ModelValidationContextBase validationContext)
        {
            return Attribute.GetErrorMessage();
        }
    }
    
  2. Créez une classe de fournisseurs d’adaptateurs qui implémente IValidationAttributeAdapterProvider.Create an adapter provider class that implements IValidationAttributeAdapterProvider. Dans la méthode GetAttributeAdapter, passez l’attribut personnalisé au constructeur de l’adaptateur, comme illustré dans cet exemple :In the GetAttributeAdapter method pass in the custom attribute to the adapter's constructor, as shown in this example:

    public class CustomValidationAttributeAdapterProvider :
        IValidationAttributeAdapterProvider
    {
        IValidationAttributeAdapterProvider baseProvider =
            new ValidationAttributeAdapterProvider();
        public IAttributeAdapter GetAttributeAdapter(ValidationAttribute attribute,
            IStringLocalizer stringLocalizer)
        {
            if (attribute is ClassicMovieAttribute)
            {
                return new ClassicMovieAttributeAdapter(
                    attribute as ClassicMovieAttribute, stringLocalizer);
            }
            else
            {
                return baseProvider.GetAttributeAdapter(attribute, stringLocalizer);
            }
        }
    }
    
  3. Inscrivez le fournisseur d’adaptateurs auprès de l’injection de dépendances dans Startup.ConfigureServices :Register the adapter provider for DI in Startup.ConfigureServices:

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

IClientModelValidator pour la validation côté clientIClientModelValidator for client-side validation

Cette méthode de rendu des attributs data- en HTML est utilisée par l’attribut ClassicMovie2 dans l’exemple d’application.This method of rendering data- attributes in HTML is used by the ClassicMovie2 attribute in the sample app. Pour ajouter la validation côté client à l’aide de cette méthodeTo add client validation by using this method:

  • Dans l’attribut de validation personnalisé, implémentez l’interface IClientModelValidator et créez une méthode AddValidation.In the custom validation attribute, implement the IClientModelValidator interface and create an AddValidation method. Dans la méthode AddValidation, ajoutez des attributs data- pour la validation, comme indiqué dans l’exemple suivant :In the AddValidation method, add data- attributes for validation, as shown in the following example:

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

Désactiver la validation côté clientDisable client-side validation

Le code suivant désactive la validation côté client dans les vues MVC :The following code disables client validation in MVC views:

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

Et dans Razor Pages :And in Razor Pages:

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

Une autre option permettant de désactiver la validation côté client consiste à commenter la référence à _ValidationScriptsPartial dans votre fichier .cshtml.Another option for disabling client validation is to comment out the reference to _ValidationScriptsPartial in your .cshtml file.

Ressources supplémentairesAdditional resources