Atsortingbuts de validation personnalisés: comparaison de deux propriétés dans le même modèle

Existe-t-il un moyen de créer un atsortingbut personnalisé dans ASP.NET Core pour valider si une propriété de date est inférieure à une autre propriété de date dans un modèle à l’aide de ValidationAtsortingbute .

Disons que j’ai ceci:

 public class MyViewModel { [Required] [CompareDates] public DateTime StartDate { get; set; } [Required] public DateTime EndDate { get; set; } = DateTime.Parse("3000-01-01"); } 

J’essaie d’utiliser quelque chose comme ceci:

  public class CompareDates : ValidationAtsortingbute { public CompareDates() : base("") { } public override bool IsValid(object value) { return base.IsValid(value); } } 

J’ai trouvé un autre poste SO qui propose d’utiliser une autre bibliothèque, mais je préfère restr avec ValidationAtsortingbute si cela est faisable.

Vous pouvez créer un atsortingbut de validation personnalisé pour comparer deux propriétés. C’est une validation côté serveur:

 public class MyViewModel { [DateLessThan("End", ErrorMessage = "Not valid")] public DateTime Begin { get; set; } public DateTime End { get; set; } } public class DateLessThanAtsortingbute : ValidationAtsortingbute { private readonly ssortingng _comparisonProperty; public DateLessThanAtsortingbute(ssortingng comparisonProperty) { _comparisonProperty = comparisonProperty; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { ErrorMessage = ErrorMessageSsortingng; var currentValue = (DateTime)value; var property = validationContext.ObjectType.GetProperty(_comparisonProperty); if (property == null) throw new ArgumentException("Property with this name not found"); var comparisonValue = (DateTime)property.GetValue(validationContext.ObjectInstance); if (currentValue > comparisonValue) return new ValidationResult(ErrorMessage); return ValidationResult.Success; } } 

Mise à jour : Si vous avez besoin d’une validation côté client pour cet atsortingbut, vous devez implémenter une interface IClientModelValidator :

 public class DateLessThanAtsortingbute : ValidationAtsortingbute, IClientModelValidator { ... public void AddValidation(ClientModelValidationContext context) { var error = FormatErrorMessage(context.ModelMetadata.GetDisplayName()); context.Atsortingbutes.Add("data-val", "true"); context.Atsortingbutes.Add("data-val-error", error); } } 

La méthode AddValidation appenda des atsortingbuts à vos entrées à partir de context.Atsortingbutes .

entrez la description de l'image ici

Vous pouvez en lire plus ici IClientModelValidator

Comme une option possible auto-validation :

Vous devez juste implémenter une interface IValidatableObject avec la méthode Validate , où vous pouvez mettre votre code de validation.

 public class MyViewModel : IValidatableObject { [Required] public DateTime StartDate { get; set; } [Required] public DateTime EndDate { get; set; } = DateTime.Parse("3000-01-01"); public IEnumerable Validate(ValidationContext validationContext) { int result = DateTime.Compare(StartDate , EndDate); if (result < 0) { yield return new ValidationResult("start date must be less than the end date!", new [] { "ConfirmEmail" }); } } } 

Vous pouvez comparer les deux dates dans la méthode IsValid.

 public class CompareDates : ValidationAtsortingbute { protected override ValidationResult IsValid(object value, ValidationContext validationContext) { //get your startdate & end date from model and value //perform comparison if (StartDate < EndDate) { return new ValidationResult ("start date must be less than the end date"); } else { return ValidationResult.Success; } } } 

Sur la base de la réponse d’Alexander Gore, je suggère une meilleure validation générique (compatible avec le kernel .Net). Lorsque vous souhaitez comparer des propriétés à l’aide de la logique GreatherThan ou LessThan (quels que soient leurs types), vous pouvez valider si elles ont implémenté l’interface IComparable . Si les deux propriétés sont valides, vous pouvez utiliser l’implémentation CompareTo . Cette règle s’applique également aux types de DateTime et d’ DateTime

Moins que

 [AtsortingbuteUsage(AtsortingbuteTargets.Property | AtsortingbuteTargets.Field | AtsortingbuteTargets.Parameter)] public class LessThanAtsortingbute : ValidationAtsortingbute { private readonly ssortingng _comparisonProperty; public LessThanAtsortingbute(ssortingng comparisonProperty) { _comparisonProperty = comparisonProperty; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { ErrorMessage = ErrorMessageSsortingng; if (value.GetType() == typeof(IComparable)) { throw new ArgumentException("value has not implemented IComparable interface"); } var currentValue = (IComparable)value; var property = validationContext.ObjectType.GetProperty(_comparisonProperty); if (property == null) { throw new ArgumentException("Comparison property with this name not found"); } var comparisonValue = property.GetValue(validationContext.ObjectInstance); if (comparisonValue.GetType() == typeof(IComparable)) { throw new ArgumentException("Comparison property has not implemented IComparable interface"); } if (!ReferenceEquals(value.GetType(), comparisonValue.GetType())) { throw new ArgumentException("The properties types must be the same"); } if (currentValue.CompareTo((IComparable)comparisonValue) >= 0) { return new ValidationResult(ErrorMessage); } return ValidationResult.Success; } } 

Plus grand que

 [AtsortingbuteUsage(AtsortingbuteTargets.Property | AtsortingbuteTargets.Field | AtsortingbuteTargets.Parameter)] public class GreaterThanAtsortingbute : ValidationAtsortingbute { private readonly ssortingng _comparisonProperty; public GreaterThanAtsortingbute(ssortingng comparisonProperty) { _comparisonProperty = comparisonProperty; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { ErrorMessage = ErrorMessageSsortingng; if (value.GetType() == typeof(IComparable)) { throw new ArgumentException("value has not implemented IComparable interface"); } var currentValue = (IComparable)value; var property = validationContext.ObjectType.GetProperty(_comparisonProperty); if (property == null) { throw new ArgumentException("Comparison property with this name not found"); } var comparisonValue = property.GetValue(validationContext.ObjectInstance); if (comparisonValue.GetType() == typeof(IComparable)) { throw new ArgumentException("Comparison property has not implemented IComparable interface"); } if (!ReferenceEquals(value.GetType(), comparisonValue.GetType())) { throw new ArgumentException("The properties types must be the same"); } if (currentValue.CompareTo((IComparable)comparisonValue) < 0) { return new ValidationResult(ErrorMessage); } return ValidationResult.Success; } } 

Dans un contexte de réservation, un exemple pourrait être le suivant:

 public DateTime CheckInDate { get; set; } [GreaterThan("CheckInDate", ErrorMessage = "CheckOutDate must be greater than CheckInDate")] public DateTime CheckOutDate { get; set; }