CodeManiac
CodeManiac

Reputation: 1014

Data Annotation for start and end date

I am using view model for start and end date and use validation using data annotation. Validation Rule are:

  1. start Date should not be greater than End Date and not null ,blank
  2. End Date should not be less than Start Date and not less than DateTime.Now and not null, blank

Following View Model consist of startdate and enddate properties. The confusion is that How can I pass value of EndDate value in StartEndDateRange data-annotation and StartDate value in data-annotation of EndDate in below code:

  public class StartEndDate
    {
        [DataType(DataType.Date)]
        [DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
        [StartEndDateRange("2000/01/01", "value of end date properties")]
        public DateTime StartDate { get; set; }

        [DataType(DataType.Date)]
        [DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
        [StartEndDateRange("value of startdate properties", DateTime.Now.ToString("yyyy/MM/dd"))]
        public DateTime EndDate { get; set; }


    }

    public class StartEndDateRangeAttribute : ValidationAttribute
    {
        private const string DateFormat = "yyyy/MM/dd";
        private const string DefaultErrorMessage =
     "'{0}' must be a date between {1:d} and {2:d}.";

        public DateTime MinDate { get; set; }
        public DateTime MaxDate { get; set; }

        public StartEndDateRangeAttribute(string minDate, string maxDate)
            : base(DefaultErrorMessage)
        {
            MinDate = ParseDate(minDate);
            MaxDate = ParseDate(maxDate);
        }

        public override bool IsValid(object value)
        {
            if (value == null || !(value is DateTime))
            {
                return true;
            }
            DateTime dateValue = (DateTime)value;
            return MinDate <= dateValue && dateValue <= MaxDate;
        }
        public override string FormatErrorMessage(string name)
        {
            return String.Format(CultureInfo.CurrentCulture,
     ErrorMessageString,
                name, MinDate, MaxDate);
        }

        private static DateTime ParseDate(string dateValue)
        {
            return DateTime.ParseExact(dateValue, DateFormat,
     CultureInfo.InvariantCulture);
        }
    }

Upvotes: 3

Views: 11959

Answers (3)

Mohayemin
Mohayemin

Reputation: 3870

Create two different Validation Attributes. One DateBefore and Another DataAfter

You can get the the properties of the model under validation from validationContext.

In the DateBefore do

protected override ValidationResult IsValid(object value, ValidationContext validationContext) {
    PropertyInfo endDateProperty= validationContext.ObjectType.GetProperty("EndDate");
    ...
}

Get the value by

var endDate = endDateProperty.GetValue(validationContext.ObjectInstance, null);

Now compare value and endDate.

Edit

A little more code

public class BeforeEndDateAttribute : ValidationAttribute{
    public string EndDatePropertyName { get; set; }
    public string StartDate { get; set; }


    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        PropertyInfo endDateProperty = validationContext.ObjectType.GetProperty(EndDatePropertyName);

        DateTime endDate = (DateTime) endDateProperty.GetValue(validationContext.ObjectInstance, null);

        var startDate = DateTime.Parse(StartDate);

        // Do comparison
        // return ValidationResult.Success; // if success
        return new ValidationResult("Error"); // if fail
    }

}

And use like:

public class MyModel
{
    [BeforeEndDate(EndDatePropertyName = "EndDate", StartDate = "2000/01/01")]
    public DateTime StartDate { get; set; }

    // [AfterStartDate(StartDatePropertyName = "StartDate", EndDate = "2020/01/01")]
    public DateTime EndDate { get; set; }
}

Upvotes: 3

VJAI
VJAI

Reputation: 32758

I may suggest you to implement the IValidatableObject in the class but only thing is you have to do the client-side validation yourself.

public class StartEndDate: IValidatableObject
{
    [Required]
    public DateTime StartDate { get; set; }

    [Required]    
    public DateTime EndDate { get; set; } 

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
       // do the validations
    }
}

Upvotes: 1

Sergei Rogovtcev
Sergei Rogovtcev

Reputation: 5832

It's easier to implement this in one validation attribute DateRange.

But if you don't want to, you'll have to override IsValid(Object, ValidationContext), extract object type being validated from ValidationContext.ObjectType, get its property being validated by ValidationContext.MemberName and then read values from attributes.

Upvotes: 1

Related Questions