206 votes

Comment utiliser IValidatableObject ?

Je comprends que `` est utilisé pour valider un objet, d’une manière que nous allons on comparer propriétés uns contre les autres.

Je voudrais toujours avoir des attributs pour valider les propriétés individuelles, mais je veux ignorer les échecs sur certaines propriétés dans certains cas.

J’essaie d’utiliser incorrectement dans le cas ci-dessous ? Si ce n’est pas le cas, comment implémenter ceci ?

202voto

zrg Points 1068

Tout d'abord, merci à @paper1337 pour m'indiquer les bonnes ressources...je ne suis pas inscrit donc je ne peux pas voter, s'il vous plaît le faire si quelqu'un d'autre lit.

Voici comment accomplir ce que j'essayais de faire.

Traitement pouvant être validé classe:

public class ValidateMe : IValidatableObject
{
    [Required]
    public bool Enable { get; set; }

    [Range(1, 5)]
    public int Prop1 { get; set; }

    [Range(1, 5)]
    public int Prop2 { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        var results = new List<ValidationResult>();
        if (this.Enable)
        {
            Validator.TryValidateProperty(this.Prop1,
                new ValidationContext(this, null, null) { MemberName = "Prop1" },
                results);
            Validator.TryValidateProperty(this.Prop2,
                new ValidationContext(this, null, null) { MemberName = "Prop2" },
                results);

            // some other random test
            if (this.Prop1 > this.Prop2)
            {
                results.Add(new ValidationResult("Prop1 must be larger than Prop2"));
            }
        }
        return results;
    }
}

À l'aide de Validator.TryValidateProperty() permettra d'ajouter les résultats de la collecte, si il y a échoué. Si il n'est pas un échec de la validation, puis rien ne sera ajouter à la collection de résultat qui est une indication de la réussite.

Faire la validation:

    public void DoValidation()
    {
        var toValidate = new ValidateMe()
        {
            Enable = true,
            Prop1 = 1,
            Prop2 = 2
        };

        bool validateAllProperties = false;

        var results = new List<ValidationResult>();

        bool isValid = Validator.TryValidateObject(
            toValidate,
            new ValidationContext(toValidate, null, null),
            results,
            validateAllProperties);
    }

Il est important de fixer validateAllProperties false pour que cette méthode fonctionne. Lors de l' validateAllProperties est faux seulement des propriétés d' [Required] d'attribut sont vérifiées. Cela permet à l' IValidatableObject.Validate() méthode de gérer la condition de validation.

87voto

Chris Shouts Points 3542

Citation de Jeff Handley du Blog sur la Validation des Objets et des Propriétés avec Validateur:

Lors de la validation d'un objet, l' le processus suivant est appliqué dans de Programme de validation.ValidateObject:

  1. Valider la propriété des attributs au niveau de
  2. Si toutes les validateurs sont invalides, abandon de validation de retour de la l'échec(s)
  3. Valider le niveau de l'objet d'attributs de
  4. Si toutes les validateurs sont invalides, abandon de validation de retour de la l'échec(s)
  5. Si sur le bureau, cadre et l'objet implémente Ivalidatableobjet, puis d'appeler sa Méthode de validation et de retourner tout l'échec(s)

Cela indique que ce que vous tentez de le faire ne fonctionne pas out-of-the-box, car la validation échouera à l'étape #2. Vous pouvez essayer de créer des attributs qui héritent de la bâtie-en un et plus précisément de vérifier la présence d'une propriété enabled (via l'interface) avant d'effectuer normalement leur validation. Alternativement, vous pourriez mettre tous de la logique de la validation de l'entité dans l' Validate méthode.

42voto

StuartLC Points 35534

Juste pour ajouter quelques points:

Notez que parce que l' Validate() signature de la méthode renvoie IEnumerable<>, yield return peut être utilisé pour paresseusement générer les résultats.

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    if (this.Enable)
    {
        // ...
        if (this.Prop1 > this.Prop2)
        {
            yield return new ValidationResult("Prop1 must be larger than Prop2");
        }

Aussi, si vous utilisez MVC ModelState, vous pouvez convertir le résultat de validation des échecs en ModelState entrées comme suit (cela peut être utile si vous faites de la validation d'un modèle de liaison personnalisé):

var resultsGroupedByMembers = validationResults
    .SelectMany(
         _ => _.MemberNames.Select(
            x => new {MemberName = x ?? "", 
                      Error = _.ErrorMessage}))
    .GroupBy(_ => _.MemberName);

foreach (var member in resultsGroupedByMembers)
{
    ModelState.AddModelError(
        member.Key,
        string.Join(". ", member.Select(_ => _.Error)));
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X