Custom Validation Attributes: Comparing two properties in the same model

前端 未结 7 428
谎友^
谎友^ 2020-12-01 06:39

Is there a way to create a custom attribute in ASP.NET Core to validate if one date property is less than other date property in a model using ValidationAttribute<

7条回答
  •  天命终不由人
    2020-12-01 06:59

    Based on Jaime answer and Jeffrey's comment regarding needing a single attribute for Less Than, Less Than or Equal to, Equal To, Greater Than, Greater Than or Equal to.

    The below code will handle all conditions with a single attribute.

    public enum ComparisonType
    {
        LessThan,
        LessThanOrEqualTo,
        EqualTo,
        GreaterThan,
        GreaterThanOrEqualTo
    }
    
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
    public class ComparisonAttribute : ValidationAttribute
    {
        private readonly string _comparisonProperty;
        private readonly ComparisonType _comparisonType;
    
        public ComparisonAttribute(string comparisonProperty, ComparisonType comparisonType)
        {
            _comparisonProperty = comparisonProperty;
            _comparisonType = comparisonType;
        }
    
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            ErrorMessage = ErrorMessageString;
    
            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");
            }
    
            bool compareToResult;
    
            switch (_comparisonType)
            {
                case ComparisonType.LessThan:
                    compareToResult = currentValue.CompareTo((IComparable) comparisonValue) >= 0;
                    break;
                case ComparisonType.LessThanOrEqualTo:
                    compareToResult = currentValue.CompareTo((IComparable) comparisonValue) > 0;
                    break;
                case ComparisonType.EqualTo:
                    compareToResult = currentValue.CompareTo((IComparable) comparisonValue) != 0;
                    break;
                case ComparisonType.GreaterThan:
                    compareToResult = currentValue.CompareTo((IComparable) comparisonValue) <= 0;
                    break;
                case ComparisonType.GreaterThanOrEqualTo:
                    compareToResult = currentValue.CompareTo((IComparable) comparisonValue) < 0;
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
    
            return compareToResult ? new ValidationResult(ErrorMessage) : ValidationResult.Success;
        }
    }
    

    In the booking context, an example would be as follows:

    public DateTime CheckInDate { get; set; }
    
    [Comparison("CheckInDate", ComparisonType.EqualTo, ErrorMessage = "CheckOutDate must be equal to CheckInDate")]
    public DateTime CheckOutDate { get; set; }
    

提交回复
热议问题