locked
Need help with custom ValidationAttribute for date range RRS feed

  • Question

  • User1001065250 posted

    I have a .net core application with a simple search page with 2 date boxes and I would like to validate the range. I have found some examples on how to do this online but the code is not working for me. The ValidationAttribute would validate against another property named in my model. The problem is that property I am looking for in the ValidationContext is always null. I have debugged it and while I expect the ValidationContext to have an object type of SearchModel, it has an object type of DateTime. 

    The below is the relevant code. SearchModel is a Razor Page model. The error occurs on if (property == null) . Does anyone have advice on how I can get the parent and access the DateOfBirthEnd property?

    public class SearchModel
    {
        [BindProperty]
        [DataType(DataType.Text)]
        [Display(Name = "First Name")]
        public string FirstName { get; set; }
    
        [BindProperty]
        [DataType(DataType.Text)]
        [Display(Name = "Last Name")]
        public string LastName { get; set; }
    
        [BindProperty]
        [Display(Name = "Date Of Birth Start")]
        [InputType(HtmlInputType.Text)]
        [Comparison("DateOfBirthEnd", ComparisonType.LessThan, ErrorMessage = "End date must be greater than start date")]
        public DateTime? DateOfBirthStart { get; set; }
    
        [BindProperty]
        [Display(Name = "Date Of Birth End")]
        [InputType(HtmlInputType.Text)]
        public DateTime? DateOfBirthEnd { get; set; }
    }
    
    
    
    [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;
        }
      }

    Friday, August 23, 2019 11:00 PM

All replies

  • User1724605321 posted

    Hi mrburnttoast79 ,

    Not reproduce ,  how do you bind the model class , is it looks like :

    BindProperty]
    public SearchModel Input { get; set; }

    And bind like :

    <div class="form-group col-md-9">
                        <label asp-for="Input.DateOfBirthStart"></label>
                        <input asp-for="Input.DateOfBirthStart" class="form-control" />
                        <span asp-validation-for="Input.DateOfBirthStart" class="text-danger"></span>
                    </div>
                    <div class="form-group col-md-9">
                        <label asp-for="Input.DateOfBirthEnd"></label>
                        <input asp-for="Input.DateOfBirthEnd" class="form-control" />
                        <span asp-validation-for="Input.DateOfBirthEnd" class="text-danger"></span>
    </div>

    It works on my side as shown below :

    Best Regards,

    Nan Yu

    Monday, August 26, 2019 3:12 AM