web-dev-qa-db-fra.com

Propriété requise de manière conditionnelle à l'aide d'annotations de données

J'ai un cours comme celui-ci:

public class Document
{
   public int DocumentType{get;set;}

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

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

Maintenant si je mets un [Required] annotation de données sur Name et Name2 propriétés, alors tout va bien et si Name ou Name2 sont vides, la validation génère une erreur.

Mais je veux que le champ Name ne soit requis que si DocumentType est égal à 1 et Name2 requis uniquement si DocumentType est égal à 2.

public class Document
{
   public int DocumentType{get;set;}

   [Required(Expression<Func<object, bool>>)]
   public string Name{get;set;}

   [Required(Expression<Func<object, bool>>)]
   public string Name2{get;set;}
}

mais je sais que je ne peux pas, cela provoque une erreur. Que dois-je faire pour cette exigence?

51
brtb

Hors de la boîte, je pense que ce n'est toujours pas possible.

Mais j’ai trouvé ceci article prometteur sur Mvc.ValidationToolkit (aussi ici , malheureusement this n’est que alpha, mais vous pourriez probablement aussi simplement extraire la ou les méthodes dont vous avez besoin de ce code et l'intégrer vous-même) , il contient l'attribut Nice sounding RequiredIf qui semble correspondre exactement votre cause:

  • vous téléchargez le projet depuis le lié au fichier et le construisez
  • récupère la dll construite à partir de votre dossier de construction et la référence dans le projet que vous utilisez
  • malheureusement, cela semble également nécessiter une référence à MVC (le moyen le plus simple de démarrer un projet MVC dans VS ou install-package Microsoft.AspNet.Mvc)
  • dans les fichiers où vous voulez l'utiliser, vous ajoutez using Mvc.ValidationToolkit;
  • alors vous êtes capable d'écrire des choses comme [RequiredIf("DocumentType", 2)] ou [RequiredIf("DocumentType", 1)], donc les objets sont valides si ni name ni name2 sont fournis tant que DocumentType n'est pas égal à 1 ou 2
6
DrCopyPaste

Attribut de validation RequiredIf

J'ai écrit un RequiredIfAttribute qui requiert une valeur de propriété particulière lorsqu'une propriété différente a une certaine valeur (ce dont vous avez besoin) ou lorsqu'une propriété différente a tout sauf une valeur spécifique.

C'est le code qui peut aider:

/// <summary>
/// Provides conditional validation based on related property value.
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public sealed class RequiredIfAttribute : ValidationAttribute
{
    #region Properties

    /// <summary>
    /// Gets or sets the other property name that will be used during validation.
    /// </summary>
    /// <value>
    /// The other property name.
    /// </value>
    public string OtherProperty { get; private set; }

    /// <summary>
    /// Gets or sets the display name of the other property.
    /// </summary>
    /// <value>
    /// The display name of the other property.
    /// </value>
    public string OtherPropertyDisplayName { get; set; }

    /// <summary>
    /// Gets or sets the other property value that will be relevant for validation.
    /// </summary>
    /// <value>
    /// The other property value.
    /// </value>
    public object OtherPropertyValue { get; private set; }

    /// <summary>
    /// Gets or sets a value indicating whether other property's value should match or differ from provided other property's value (default is <c>false</c>).
    /// </summary>
    /// <value>
    ///   <c>true</c> if other property's value validation should be inverted; otherwise, <c>false</c>.
    /// </value>
    /// <remarks>
    /// How this works
    /// - true: validated property is required when other property doesn't equal provided value
    /// - false: validated property is required when other property matches provided value
    /// </remarks>
    public bool IsInverted { get; set; }

    /// <summary>
    /// Gets a value that indicates whether the attribute requires validation context.
    /// </summary>
    /// <returns><c>true</c> if the attribute requires validation context; otherwise, <c>false</c>.</returns>
    public override bool RequiresValidationContext
    {
        get { return true; }
    }

    #endregion

    #region Constructor

    /// <summary>
    /// Initializes a new instance of the <see cref="RequiredIfAttribute"/> class.
    /// </summary>
    /// <param name="otherProperty">The other property.</param>
    /// <param name="otherPropertyValue">The other property value.</param>
    public RequiredIfAttribute(string otherProperty, object otherPropertyValue)
        : base("'{0}' is required because '{1}' has a value {3}'{2}'.")
    {
        this.OtherProperty = otherProperty;
        this.OtherPropertyValue = otherPropertyValue;
        this.IsInverted = false;
    }

    #endregion

    /// <summary>
    /// Applies formatting to an error message, based on the data field where the error occurred.
    /// </summary>
    /// <param name="name">The name to include in the formatted message.</param>
    /// <returns>
    /// An instance of the formatted error message.
    /// </returns>
    public override string FormatErrorMessage(string name)
    {
        return string.Format(
            CultureInfo.CurrentCulture,
            base.ErrorMessageString,
            name,
            this.OtherPropertyDisplayName ?? this.OtherProperty,
            this.OtherPropertyValue,
            this.IsInverted ? "other than " : "of ");
    }

    /// <summary>
    /// Validates the specified value with respect to the current validation attribute.
    /// </summary>
    /// <param name="value">The value to validate.</param>
    /// <param name="validationContext">The context information about the validation operation.</param>
    /// <returns>
    /// An instance of the <see cref="T:System.ComponentModel.DataAnnotations.ValidationResult" /> class.
    /// </returns>
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (validationContext == null)
        {
            throw new ArgumentNullException("validationContext");
        }

        PropertyInfo otherProperty = validationContext.ObjectType.GetProperty(this.OtherProperty);
        if (otherProperty == null)
        {
            return new ValidationResult(
                string.Format(CultureInfo.CurrentCulture, "Could not find a property named '{0}'.", this.OtherProperty));
        }

        object otherValue = otherProperty.GetValue(validationContext.ObjectInstance);

        // check if this value is actually required and validate it
        if (!this.IsInverted && object.Equals(otherValue, this.OtherPropertyValue) ||
            this.IsInverted && !object.Equals(otherValue, this.OtherPropertyValue))
        {
            if (value == null)
            {
                return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
            }

            // additional check for strings so they're not empty
            string val = value as string;
            if (val != null && val.Trim().Length == 0)
            {
                return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
            }
        }

        return ValidationResult.Success;
    }
}
74
Robert Koritnik

propriété requise de manière conditionnelle à l'aide d'annotations de données

 [RequiredIf(dependent Property name, dependent Property value)]

e.g. 


 [RequiredIf("Country", "Ethiopia")]
 public string POBox{get;set;}
 // POBox is required in Ethiopia
 public string Country{get;set;}

 [RequiredIf("destination", "US")]
 public string State{get;set;}
 // State is required in US

 public string destination{get;set;}



public class RequiredIfAttribute : ValidationAttribute
{
    RequiredAttribute _innerAttribute = new RequiredAttribute();
    public string _dependentProperty { get; set; }
    public object _targetValue { get; set; }

    public RequiredIfAttribute(string dependentProperty, object targetValue)
    {
        this._dependentProperty = dependentProperty;
        this._targetValue = targetValue;
    }
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var field = validationContext.ObjectType.GetProperty(_dependentProperty);
        if (field != null)
        {
            var dependentValue = field.GetValue(validationContext.ObjectInstance, null);
            if ((dependentValue == null && _targetValue == null) || (dependentValue.Equals(_targetValue)))
            {
                if (!_innerAttribute.IsValid(value))
                {
                    string name = validationContext.DisplayName;
                    return new ValidationResult(ErrorMessage=name + " Is required.");
                }
            }
            return ValidationResult.Success;
        }
        else
        {
            return new ValidationResult(FormatErrorMessage(_dependentProperty));
        }
    }
}
20
Ghebrehiywet

Découvrez la validation courante

https://www.nuget.org/packages/FluentValidation/

Description du projet Une petite bibliothèque de validation pour .NET qui utilise une interface fluide et des expressions lambda pour créer des règles de validation pour vos objets métier.

https://github.com/JeremySkinner/FluentValidation

4
Chris McKelt

Départ MVC Foolproof validation. Il a des annotations de données dans le modèle comme RequiredIf (Propriété dépendante, valeur dépendante) si je me souviens bien. Vous pouvez télécharger Foolproof à partir de:
Visual Studio (2017) -> Outils -> Gestionnaire de packages Nuget -> Gérer les packages Nuget pour la solution. Référence mvcfoolproof.unobtrusive.min.js en plus des fichiers jquery.

1
Jaggan_j

J'ai toujours utilisé IValidatableObject de System.ComponentModel.DataAnnotations;

Exemple ci-dessous

  public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            if (this.SendInAppNotification)
            {
                if (string.IsNullOrEmpty(this.NotificationTitle) || string.IsNullOrWhiteSpace(this.NotificationTitle))
                {
                    yield return new ValidationResult(
                        $"Notification Title is required",
                        new[] { nameof(this.NotificationTitle) });
                }
            }
0
chris castle