Validation de modèle dans ASP.NET Core MVCModel validation in ASP.NET Core MVC

Par Rachel AppelBy Rachel Appel

Introduction à la validation de modèleIntroduction to model validation

Avant qu’une application stocke des données dans une base de données, l’application doit valider les données.Before an app stores data in a database, the app must validate the data. L’application doit vérifier que les données ne contiennent pas de menaces de sécurité potentielles, et qu’elles sont mises en forme de façon appropriée quand au type et à la taille. Elles doivent aussi être conformes à vos règles.Data must be checked for potential security threats, verified that it's appropriately formatted by type and size, and it must conform to your rules. La validation est nécessaire même si son implémentation peut être fastidieuse et redondante.Validation is necessary although it can be redundant and tedious to implement. Dans MVC, la validation se produit à la fois sur le client et sur le serveur.In MVC, validation happens on both the client and server.

Heureusement, .NET dispose d’une validation abstraite dans des attributs de validation.Fortunately, .NET has abstracted validation into validation attributes. Ces attributs contiennent un code de validation, ce qui réduit la quantité de code à écrire.These attributes contain validation code, thereby reducing the amount of code you must write.

Dans ASP.NET Core 2.2 et ultérieur, le runtime ASP.NET Core court-circuite (ignore) la validation s’il détermine qu’un graphe de modèle donné n’a pas besoin de validation.In ASP.NET Core 2.2 and later, the ASP.NET Core runtime short-circuits (skips) validation if it can determine that a given model graph doesn't require validation. Cela peut déboucher sur une amélioration significative des performances lors de la validation de modèles qui ne peuvent pas avoir de validateurs associés ou qui n’en ont pas.Skipping validation can provide significant performance improvements when validating models that cannot or do not have any associated validators. La validation ignorée inclut des objets comme des collections de primitifs (byte[], string[], Dictionary<string, string>, etc.) ou des graphes d’objets complexes sans validateurs.The skipped validation includes objects such as collections of primitives (byte[], string[], Dictionary<string, string>, etc.), or complex object graphs without any validators.

Affichez ou téléchargez un exemple depuis GitHub.View or download sample from GitHub.

Attributs de validationValidation Attributes

Les attributs de validation sont un moyen de configurer la validation de modèle : elle est donc conceptuellement similaire à la validation des champs dans les tables de base de données.Validation attributes are a way to configure model validation so it's similar conceptually to validation on fields in database tables. Ceci inclut des contraintes comme l’affectation de types de données ou des champs obligatoires.This includes constraints such as assigning data types or required fields. L’application de modèles aux données pour forcer le respect des règles d’entreprise, comme une carte de crédit, un numéro de téléphone ou une adresse e-mail, est un autre type de validation.Other types of validation include applying patterns to data to enforce business rules, such as a credit card, phone number, or email address. Les attributs de validation simplifient et facilitent l’application de ces exigences.Validation attributes make enforcing these requirements much simpler and easier to use.

Les attributs de validation sont spécifiés au niveau de la propriété :Validation attributes are specified at the property level:

[Required]
public string MyProperty { get; set; } 

Voici un modèle Movie annoté pour une application qui stocke des informations sur les films et les émissions de télévision.Below is an annotated Movie model from an app that stores information about movies and TV shows. La plupart des propriétés sont obligatoires et plusieurs propriétés de type chaîne sont soumises à des exigences en matière de longueur.Most of the properties are required and several string properties have length requirements. En outre, une restriction de plage numérique de 0 à 999,99 $ est en place pour la propriété Price, ainsi qu’un attribut de validation personnalisé.Additionally, there's a numeric range restriction in place for the Price property from 0 to $999.99, along with a custom validation 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; }
}

Une simple lecture du modèle révèle les règles concernant les données de cette application, facilitant ainsi la maintenance du code.Simply reading through the model reveals the rules about data for this app, making it easier to maintain the code. Voici plusieurs attributs de validation intégrés courants :Below are several popular built-in validation attributes:

  • [CreditCard] : vérifie que la propriété a un format de carte de crédit.[CreditCard]: Validates the property has a credit card format.

  • [Compare] : vérifie que deux propriétés d’un modèle sont en correspondance.[Compare]: Validates two properties in a model match.

  • [EmailAddress] : vérifie que la propriété a un format d’e-mail.[EmailAddress]: Validates 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 the property has a telephone format.

  • [Range] : vérifie que la valeur de la propriété est dans la plage donnée.[Range]: Validates the property value falls within the given range.

  • [RegularExpression] : vérifie que les données correspondent à l’expression régulière spécifiée.[RegularExpression]: Validates that the data matches the specified regular expression.

  • [Required] : rend une propriété obligatoire.[Required]: Makes a property required.

  • [StringLength] : vérifie que la longueur d’une propriété de type chaîne est au plus la longueur maximale spécifiée.[StringLength]: Validates that a string property has at most the given maximum length.

  • [Url] : vérifie que la propriété a un format d’URL.[Url]: Validates the property has a URL format.

MVC prend en charge tout attribut dérivant de ValidationAttribute à des fins de validation.MVC supports any attribute that derives from ValidationAttribute for validation purposes. Vous pouvez trouver de nombreux attributs de validation utiles dans l’espace de noms System.ComponentModel.DataAnnotations.Many useful validation attributes can be found in the System.ComponentModel.DataAnnotations namespace.

Pour certaines, vous pouvez avoir besoin de plus de fonctionnalités que celles fournies par les attributs prédéfinis.There may be instances where you need more features than built-in attributes provide. Dans ces cas, vous pouvez créer des attributs de validation personnalisés en dérivant depuis ValidationAttribute ou en modifiant votre modèle pour implémenter IValidatableObject.For those times, you can create custom validation attributes by deriving from ValidationAttribute or changing your model to implement IValidatableObject.

Remarques sur l’utilisation de l’attribut RequiredNotes on the use of the Required attribute

Les types valeur non Nullable (tels que decimal, int, float et DateTime) sont obligatoires par nature et n’ont pas besoin de l’attribut Required.Non-nullable value types (such as decimal, int, float, and DateTime) are inherently required and don't need the Required attribute. L’application n’effectue pas de vérifications de validation côté serveur pour les types non Nullables qui sont marqués Required.The app performs no server-side validation checks for non-nullable types that are marked Required.

La liaison de modèle MVC, qui n’est pas concernée par la validation et les attributs de validation, rejette l’envoi d’un champ de formulaire contenant une valeur manquante ou un espace pour un type non Nullable.MVC model binding, which isn't concerned with validation and validation attributes, rejects a form field submission containing a missing value or whitespace for a non-nullable type. En l’absence d’un attribut BindRequired sur la propriété cible, la liaison de modèle ignore les données manquantes pour les types non Nullables, où le champ de formulaire est absent dans les données du formulaire entrant.In the absence of a BindRequired attribute on the target property, model binding ignores missing data for non-nullable types, where the form field is absent from the incoming form data.

L’attribut BindRequired (consultez également Liaison de données dans ASP.NET Core) est pratique pour vérifier que les données d’un formulaire sont complètes.The BindRequired attribute (also see Liaison de données dans ASP.NET Core) is useful to ensure form data is complete. Quand il est appliqué à une propriété, le système de la liaison de modèle exige une valeur pour cette propriété.When applied to a property, the model binding system requires a value for that property. Quand il est appliqué à un type, le système de la liaison de modèle exige des valeurs pour toutes les propriétés de ce type.When applied to a type, the model binding system requires values for all of the properties of that type.

Quand vous utilisez un type Nullable<T> (par exemple decimal? ou System.Nullable<decimal>) et que vous le marquez Required, une vérification de la validation côté serveur est effectuée comme si la propriété était de type nullable standard (par exemple string).When you use a Nullable<T> type (for example, decimal? or System.Nullable<decimal>) and mark it Required, a server-side validation check is performed as if the property were a standard nullable type (for example, a string).

La validation côté client nécessite une valeur pour un champ de formulaire qui correspond à une propriété du modèle que vous avez marquée Required et pour une propriété de type non Nullable que vous n’avez pas marquée Required.Client-side validation requires a value for a form field that corresponds to a model property that you've marked Required and for a non-nullable type property that you haven't marked Required. Required peut être utilisé pour contrôler le message d’erreur de validation côté client.Required can be used to control the client-side validation error message.

État du modèleModel State

L’état du modèle représente les erreurs de validation dans les valeurs du formulaire HTML envoyé.Model state represents validation errors in submitted HTML form values.

MVC continue la validation des champs jusqu’à ce que le nombre maximal d’erreurs soit atteint (200 par défaut).MVC will continue validating fields until it reaches the maximum number of errors (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);

Gérer les erreurs d’état de modèleHandle Model State errors

La validation de modèle se produit avant l’exécution d’une action de contrôleur.Model validation occurs before the execution of a controller action. Il incombe à l’action d’inspecter ModelState.IsValid et de réagir de façon appropriée.It's the action's responsibility to inspect ModelState.IsValid and react appropriately. Dans de nombreux cas, la réaction appropriée est de retourner une réponse d’erreur, dans l’idéal en détaillant la raison de l’échec de validation du modèle.In many cases, the appropriate reaction is to return an error response, ideally detailing the reason why model validation failed.

Quand ModelState.IsValid prend la valeur false dans les contrôleurs d’API web à l’aide de l’attribut [ApiController], une réponse HTTP 400 automatique contenant les détails du problème est retournée.When ModelState.IsValid evaluates to false in web API controllers using the [ApiController] attribute, an automatic HTTP 400 response containing issue details is returned. Pour plus d’informations, consultez Réponses HTTP 400 automatiques.For more information, see Automatic HTTP 400 responses.

Certaines applications choisissent de suivre une convention standard pour traiter les erreurs de validation de modèle ; dans ce cas, un filtre peut être un emplacement approprié pour implémenter une telle stratégie.Some apps will choose to follow a standard convention for dealing with model validation errors, in which case a filter may be an appropriate place to implement such a policy. Vous devez tester le comportement de vos actions avec des états de modèle valides et non valides.You should test how your actions behave with valid and invalid model states.

Validation manuelleManual validation

Une fois la liaison de modèle et la validation terminées, vous pouvez en répéter des parties.After model binding and validation are complete, you may want to repeat parts of it. Par exemple, un utilisateur peut avoir entré du texte dans un champ qui attendait un entier, ou il peut être nécessaire de calculer une valeur pour une propriété du modèle.For example, a user may have entered text in a field expecting an integer, or you may need to compute a value for a model's property.

Il peut être nécessaire d’effectuer la validation manuellement.You may need to run validation manually. Pour cela, appelez la méthode TryValidateModel, comme indiqué ici :To do so, call the TryValidateModel method, as shown here:

TryValidateModel(movie);

Validation personnaliséeCustom validation

Les attributs de validation fonctionnent pour la plupart des besoins de validation.Validation attributes work for most validation needs. Certaines règles de validation sont cependant spécifiques à votre métier.However, some validation rules are specific to your business. Vos règles peuvent ne pas être des techniques de validation de données courantes comme vérifier qu’un champ est obligatoire ou qu’il est conforme à une plage de valeurs.Your rules might not be common data validation techniques such as ensuring a field is required or that it conforms to a range of values. Pour ces scénarios, les attributs de validation personnalisés sont une bonne solution.For these scenarios, custom validation attributes are a great solution. Vous pouvez créer facilement vos propres attributs de validation personnalisée dans MVC.Creating your own custom validation attributes in MVC is easy. Héritez simplement de ValidationAttribute et remplacez la méthode IsValid.Just inherit from the ValidationAttribute, and override the IsValid method. La méthode IsValid accepte deux paramètres, le premier est un objet nommé value et le second est un objet ValidationContext nommé validationContext.The IsValid method accepts two parameters, the first is an object named value and the second is a ValidationContext object named validationContext. value fait référence à la valeur réelle du champ que votre validateur personnalisé doit valider.Value refers to the actual value from the field that your custom validator is validating.

Dans l’exemple suivant, une règle métier stipule que les utilisateurs ne peuvent pas définir le genre sur Classic pour un film sorti après 1960.In the following sample, a business rule states that users may not set the genre to Classic for a movie released after 1960. L’attribut [ClassicMovie] vérifie d’abord le genre et, s’il s’agit d’un classique, vérifie ensuite si date de sortie est postérieure à 1960.The [ClassicMovie] attribute checks the genre first, and if it's a classic, then it checks the release date to see that it's later than 1960. Si la sortie est postérieure à 1960, la validation échoue.If it's released after 1960, validation fails. L’attribut accepte un paramètre entier qui représente l’année que vous pouvez utiliser pour valider les données.The attribute accepts an integer parameter representing the year that you can use to validate data. Vous pouvez capturer la valeur du paramètre dans le constructeur de l’attribut, comme illustré ici :You can capture the value of the parameter in the attribute's constructor, as shown here:

public class ClassicMovieAttribute : ValidationAttribute, IClientModelValidator
{
    private int _year;

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

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

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

        return ValidationResult.Success;
    }

La variable movie ci-dessus représente un objet Movie qui contient les données de l’envoi du formulaire à valider.The movie variable above represents a Movie object that contains the data from the form submission to validate. Dans ce cas, le code de validation vérifie la date et le genre dans la méthode IsValid de la classe ClassicMovieAttribute selon les règles définies.In this case, the validation code checks the date and genre in the IsValid method of the ClassicMovieAttribute class as per the rules. 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:

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

Quand un utilisateur modifie le champ Genre et envoie le formulaire, la méthode IsValid de la classe ClassicMovieAttribute doit vérifier si le film est un classique.When a user modifies the Genre field and submits the form, the IsValid method of the ClassicMovieAttribute will verify whether the movie is a classic. Comme pour tout attribut prédéfini, appliquez ClassicMovieAttribute à une propriété comme ReleaseDate pour garantir que la validation se produit, comme illustré dans l’exemple de code précédent.Like any built-in attribute, apply the ClassicMovieAttribute to a property such as ReleaseDate to ensure validation happens, as shown in the previous code sample. Étant donné que l’exemple fonctionne seulement avec les types Movie, une meilleure option consiste à utiliser IValidatableObject comme illustré dans le paragraphe suivant.Since the example works only with Movie types, a better option is to use IValidatableObject as shown in the following paragraph.

Vous pouvez aussi placer ce même code dans le modèle en implémentant la méthode Validate sur l’interface IValidatableObject.Alternatively, this same code could be placed in the model by implementing the Validate method on the IValidatableObject interface. Si les attributs de validation personnalisés fonctionnent bien pour la validation de propriétés individuelles, vous pouvez aussi utiliser l’implémentation de IValidatableObject pour implémenter une validation au niveau de la classe, comme illustré ci-après.While custom validation attributes work well for validating individual properties, implementing IValidatableObject can be used to implement class-level validation as seen here.

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 côté clientClient side validation

La validation côté client est très pratique pour les utilisateurs.Client side validation is a great convenience for users. Elle leur épargne le temps d’attente nécessaire à un aller-retour avec le serveur.It saves time they would otherwise spend waiting for a round trip to the server. En termes d’activité de l’entreprise, même de quelques fractions de secondes multipliées des centaines de fois par jour finissent par représenter un temps considérable, auquel s’ajoute un coût et de la frustration.In business terms, even a few fractions of seconds multiplied hundreds of times each day adds up to be a lot of time, expense, and frustration. Une validation directe et immédiate permet aux utilisateurs de travailler plus efficacement, et de produire une meilleure qualité des entrées et des sorties.Straightforward and immediate validation enables users to work more efficiently and produce better quality input and output.

Vous devez disposer d’une vue avec les références de script JavaScript appropriées en place pour que la validation côté client fonctionne comme vous le voyez ici.You must have a view with the proper JavaScript script references in place for client side validation to work as you see here.

<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.2.0.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.16.0/jquery.validate.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.6/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 (les exemples de méthode validate() de jQuery Validate montrent combien ceci peut devenir complexe).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 (the examples for jQuery Validate's validate() method shows how complex this could become). Au lieu de cela, les Tag Helpers et les helpers HTML peuvent utiliser les attributs de validation et les métadonnées de type des propriétés du modèle pour rendre les attributs data- HTML 5 dans les éléments de formulaire nécessitant une validation.Instead, MVC's Tag Helpers and HTML helpers are able to use the validation attributes and type metadata from model properties to render HTML 5 data- attributes in the form elements that need validation. MVC génère les attributs data- pour les attributs intégrés et pour les attributs personnalisés.MVC generates the data- attributes for both built-in and custom attributes. jQuery Unobtrusive Validation analyse ensuite les attributs data- et passe la logique à jQuery Validate, en « copiant » la logique de validation côté serveur vers le client.jQuery Unobtrusive Validation then 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 les Tag Helpers appropriés, comme indiqué ici :You can display validation errors on the client using the relevant 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 ci-dessus rendent le HTML ci-dessous.The tag helpers above render the HTML below. 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 ci-dessous contient un message d’erreur à afficher si l’utilisateur ne renseigne pas le champ correspondant à la date de sortie.The data-val-required attribute below 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.

<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>

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.

MVC détermine les valeurs d’attribut de type en fonction du type de données .NET d’une propriété, éventuellement remplacé avec des attributs [DataType].MVC determines type attribute values based on the .NET data type of a property, possibly overridden using [DataType] attributes. L’attribut [DataType] de base ne fait pas de validation côté serveur réelle.The base [DataType] attribute does no real server-side validation. Les navigateurs choisissent eux-mêmes leurs propres messages d’erreur et affichent ces erreurs ; le package jQuery Unobtrusive Validation peut cependant remplacer les messages et les afficher de façon cohérente avec d’autres messages.Browsers choose their own error messages and display those errors as they wish, however the jQuery Validation Unobtrusive package can override the messages and display them consistently with others. Ceci se produit de façon plus évidente quand des utilisateurs appliquent des sous-classes [DataType] comme [EmailAddress].This happens most obviously when users apply [DataType] subclasses such as [EmailAddress].

Ajouter une validation à des formulaires dynamiquesAdd Validation to Dynamic Forms

Comme jQuery Unobtrusive Validation passe la logique et les paramètres de validation à jQuery Validate lors du premier chargement de la page, les formulaires générés dynamiquement ne se présentent pas automatiquement à la validation.Because jQuery Unobtrusive Validation passes validation logic and parameters to jQuery Validate when the page first loads, dynamically generated forms won't automatically exhibit validation. Au lieu de cela, vous devez indiquer à jQuery Validate d’analyser le formulaire dynamique immédiatement après sa création.Instead, you must tell jQuery Unobtrusive Validation to parse the dynamic form immediately after creating it. Par exemple, le code ci-dessous montre comment vous pouvez configurer la validation côté client sur un formulaire ajouté via AJAX.For example, the code below shows how you might set 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 pour que le formulaire présente les règles de validation souhaitées côté client.The values of those attributes are then passed to the jQuery Validate plugin so that the form exhibits the desired client side validation rules.

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

Vous pouvez aussi mettre à jour les règles de validation sur un formulaire quand des contrôles individuels, comme <input/> et <select/>, sont générés dynamiquement.You can also update the validation rules on a form when individual controls, such as <input/>s and <select/>s, are dynamically generated. Vous ne pouvez pas passer de sélecteurs pour ces éléments directement à la méthode parse(), car le formulaire entourant a déjà été analysé et ne sera pas mis à jour.You cannot pass selectors for these elements to the parse() method directly because the surrounding form has already been parsed and won't update. Au lieu de cela, vous supprimez d’abord les données de validation existantes, puis vous réanalysez tout le formulaire, comme indiqué ci-dessous :Instead, you first remove the existing validation data, then reparse the entire form, as shown below:

$.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);
    }
})

IClientModelValidatorIClientModelValidator

Vous pouvez créer une logique côté client pour votre attribut personnalisé, et la validation discrète qui crée un adaptateur pour la validation jquery l’exécute sur le client automatiquement pour vous dans le cadre de la validation.You may create client side logic for your custom attribute, and unobtrusive validation which creates an adapter to jquery validation will execute it on the client for you automatically as part of validation. La première étape consiste à contrôler quels attributs data- sont ajoutés en implémentant l’interface IClientModelValidator comme indiqué ici :The first step is to control what data- attributes are added by implementing the IClientModelValidator interface as shown here:

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

Les attributs qui implémentent cette interface peuvent ajouter des attributs HTML aux champs générés.Attributes that implement this interface can add HTML attributes to generated fields. L’examen de la sortie pour l’élément ReleaseDate révèle du HTML qui est similaire à l’exemple précédent, excepté qu’il existe maintenant un attribut data-val-classicmovie qui a été défini dans la méthode AddValidation de IClientModelValidator.Examining the output for the ReleaseDate element reveals HTML that's similar to the previous example, except now there's a data-val-classicmovie attribute that was defined in the AddValidation method of IClientModelValidator.

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

La validation discrète utilise les données de l’attribut data- pour afficher les messages d’erreur.Unobtrusive validation uses the data in the data- attributes to display error messages. Cependant, jQuery ne dispose pas des règles ou des messages tant que vous ne les avez pas ajoutés à l’objet validator de jQuery.However, jQuery doesn't know about rules or messages until you add them to jQuery's validator object. Cela est illustré dans l’exemple suivant, qui ajoute une méthode de validation client classicmovie personnalisée pour l’objet validator jQuery.This is shown in the following example, which adds a custom classicmovie client validation method to the jQuery validator object. Pour obtenir une explication de la méthode unobtrusive.adapters.add, consultez Validation client non obstrusive dans ASP.NET MVC.For an explanation of the unobtrusive.adapters.add method, see Unobtrusive Client Validation in ASP.NET MVC.

$.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.getFullYear() <= 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;
    });

Avec le code précédent, la méthode classicmovie effectue la validation côté client à la date de mise en production du film.With the preceding code, the classicmovie method performs client-side validation on the movie release date. Le message d’erreur s’affiche si la méthode retourne false.The error message displays if the method returns false.

Validation à distanceRemote validation

La validation à distance est une fonctionnalité intéressante à utiliser quand vous devez valider des données sur le client relativement à des données présentes sur le serveur.Remote validation is a great feature to use when you need to validate data on the client against data on the server. Par exemple, votre application doit vérifier si une adresse e-mail ou un nom d’utilisateur est déjà utilisé, et elle doit pour cela interroger une grande quantité de données.For example, your app may need to verify whether an email or user name is already in use, and it must query a large amount of data to do so. Le téléchargement de grands jeux de données pour valider un seul champ ou même quelques-uns consomme trop de ressources.Downloading large sets of data for validating one or a few fields consumes too many resources. Il peut également exposer des informations sensibles.It may also expose sensitive information. Une alternative consiste à faire une demande aller-retour pour valider un champ.An alternative is to make a round-trip request to validate a field.

Vous pouvez implémenter une validation à distance selon un processus en deux étapes.You can implement remote validation in a two step process. Vous devez d’abord annoter votre modèle avec l’attribut [Remote].First, you must annotate your model with the [Remote] attribute. L’attribut [Remote] accepte plusieurs surcharges que vous pouvez utiliser pour diriger le code JavaScript côté client vers le code approprié à appeler.The [Remote] attribute accepts multiple overloads you can use to direct client side JavaScript to the appropriate code to call. L’exemple ci-dessous pointe vers la méthode d’action VerifyEmail du contrôleur Users.The example below points to the VerifyEmail action method of the Users controller.

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

La deuxième étape consiste à placer le code de validation dans la méthode d’action correspondante comme défini dans l’attribut [Remote].The second step is putting the validation code in the corresponding action method as defined in the [Remote] attribute. Selon la documentation sur la méthode jQuery Validate distante, la réponse du serveur doit être une chaîne JSON qui est :According to the jQuery Validate remote method documentation, the server response must be a JSON string that's either:

  • "true" pour les éléments valides."true" for valid elements.
  • "false", undefined ou null pour les éléments non valides, avec le message d’erreur par défaut."false", undefined, or null for invalid elements, using the default error message.

Si la réponse du serveur est une chaîne (par exemple, "That name is already taken, try peter123 instead"), la chaîne est affichée comme un message d’erreur personnalisé à la place de la chaîne par défaut.If the server response is a string (for example, "That name is already taken, try peter123 instead"), the string is displayed as a custom error message in place of the default string.

La définition de la méthode VerifyEmail suit ces règles, comme indiqué ci-dessous.The definition of the VerifyEmail method follows these rules, as shown below. Elle retourne un message d’erreur de validation si l’adresse e-mail est déjà utilisée ou true si l’adresse e-mail est libre, et elle encapsule le résultat dans un objet JsonResult.It returns a validation error message if the email is taken, or true if the email is free, and wraps the result in a JsonResult object. Le côté client peut alors utiliser la valeur retournée pour continuer ou afficher l’erreur si nécessaire.The client side can then use the returned value to proceed or display the error if needed.

[AcceptVerbs("Get", "Post")]
public IActionResult VerifyEmail(string email)
{
    if (!_userRepository.VerifyEmail(email))
    {
        return Json($"Email {email} is already in use.");
    }

    return Json(true);
}

Maintenant, quand les utilisateurs entrent une adresse e-mail, le code JavaScript de la vue effectue un appel à distance pour vérifier si l’e-mail a déjà été utilisé et, le cas échéant, affiche le message d’erreur.Now when users enter an email, JavaScript in the view makes a remote call to see if that email has been taken and, if so, displays the error message. Dans le cas contraire, l’utilisateur peut envoyer le formulaire comme d’habitude.Otherwise, the user can submit the form as usual.

La propriété AdditionalFields de l’attribut [Remote] est pratique pour valider des combinaisons de champs relativement à des données présentes sur le serveur.The AdditionalFields property of the [Remote] attribute is useful for validating combinations of fields against data on the server. Par exemple, si le modèle User ci-dessus a deux propriétés supplémentaires appelées 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 from above had two additional properties called FirstName and LastName, you might want to verify that no existing users already have that pair of names. Vous définissez les nouvelles propriétés comme indiqué dans le code suivant :You define the new properties as shown in the following code:

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

AdditionalFields peut avoir été défini explicitement avec les chaînes "FirstName" et "LastName", mais l’utilisation de l’opérateur nameof de cette façon simplifie la refactorisation ultérieure.AdditionalFields could've been set explicitly to the strings "FirstName" and "LastName", but using the nameof operator like this simplifies later refactoring. La méthode d’action pour effectuer la validation doit alors accepter deux arguments, un pour la valeur de FirstName et l’autre pour la valeur de LastName.The action method to perform the validation must then accept two arguments, one for the value of FirstName and one for the value of LastName.

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

Maintenant, quand des utilisateurs entrent un prénom et un nom, JavaScript :Now when users enter a first and last name, JavaScript:

  • Effectue un appel à distance pour vérifier si cette paire de noms est déjà utilisée.Makes a remote call to see if that pair of names has been taken.
  • Si la paire est déjà utilisée, un message d’erreur est affiché.If the pair has been taken, an error message is displayed.
  • Si elle n’est pas déjà utilisée, l’utilisateur peut envoyer le formulaire.If not taken, the user can submit the form.

Si vous devez valider deux champs supplémentaires ou plus avec l’attribut [Remote], vous les fournissez sous la forme d’une liste délimitée par des virgules.If you need to validate two or more additional fields with the [Remote] attribute, you 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 le code suivant :For example, to add a MiddleName property to the model, set the [Remote] attribute as shown in the following code:

[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. Par conséquent, vous ne devez pas utiliser une chaîne interpolée ou appeler string.Join() pour initialiser AdditionalFields.Therefore, you must not use an interpolated string or call string.Join() to initialize AdditionalFields. Pour chaque champ supplémentaire que vous ajoutez à l’attribut [Remote], vous devez ajouter un autre argument à la méthode d’action de contrôleur correspondante.For every additional field that you add to the [Remote] attribute, you must add another argument to the corresponding controller action method.