.NET MVC Custom Date Validator

14,926

Solution 1

public sealed class DateStartAttribute : ValidationAttribute
{
    public override bool IsValid(object value)
    {
        DateTime dateStart = (DateTime)value;
        // Meeting must start in the future time.
        return (dateStart > DateTime.Now);
    }
}

public sealed class DateEndAttribute : ValidationAttribute
{
    public string DateStartProperty { get; set; }
    public override bool IsValid(object value)
    {
        // Get Value of the DateStart property
        string dateStartString = HttpContext.Current.Request[DateStartProperty];
        DateTime dateEnd = (DateTime)value;
        DateTime dateStart = DateTime.Parse(dateStartString);

        // Meeting start time must be before the end time
        return dateStart < dateEnd;
    }
}

and in your View Model:

[DateStart]
public DateTime StartDate{ get; set; }

[DateEnd(DateStartProperty="StartDate")]
public DateTime EndDate{ get; set; }

In your action, just check that ModelState.IsValid. That what you're after?

Solution 2

I know this post is older, but, this solution I found is much better.

The accepted solution in this post won't work if the object has a prefix when it is part of a viewmodel.

i.e. the lines

// Get Value of the DateStart property
string dateStartString = HttpContext.Current.Request[DateStartProperty];

A better solution can be found here: ASP .NET MVC 3 Validation using Custom DataAnnotation Attribute:

New DateGreaterThan attribute:

public sealed class DateGreaterThanAttribute : ValidationAttribute
{
    private const string _defaultErrorMessage = "'{0}' must be greater than '{1}'";
    private string _basePropertyName;

    public DateGreaterThanAttribute(string basePropertyName) : base(_defaultErrorMessage)
    {
        _basePropertyName = basePropertyName;
    }

    //Override default FormatErrorMessage Method
    public override string FormatErrorMessage(string name)
    {
        return string.Format(_defaultErrorMessage, name, _basePropertyName);
    }

    //Override IsValid
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        //Get PropertyInfo Object
        var basePropertyInfo = validationContext.ObjectType.GetProperty(_basePropertyName);

        //Get Value of the property
        var startDate = (DateTime)basePropertyInfo.GetValue(validationContext.ObjectInstance, null);

        var thisDate = (DateTime)value;

        //Actual comparision
        if (thisDate <= startDate)
        {
            var message = FormatErrorMessage(validationContext.DisplayName);
            return new ValidationResult(message);
        }

        //Default return - This means there were no validation error
        return null;
    }
}

Usage example:

[Required]
[DataType(DataType.DateTime)]
[Display(Name = "StartDate")]
public DateTime StartDate { get; set; }

[Required]
[DataType(DataType.DateTime)]
[Display(Name = "EndDate")]
[DateGreaterThanAttribute("StartDate")]
public DateTime EndDate { get; set; }
Share:
14,926
MrBliz
Author by

MrBliz

Updated on June 01, 2022

Comments

  • MrBliz
    MrBliz almost 2 years

    I'll be tackling writing a custom date validation class tomorrow for a meeting app i'm working on at work that will validate if a given start or end date is A) less than the current date, or B) the start date is greater than the end date of the meeting (or vice versa).

    I think this is probably a fairly common requirement. Can anyone point me in the direction of a blog post that might help me out in tackling this problem?

    I'm using .net 3.5 so i can't use the new model validator api built into .NET 4. THe project i'm working on is MVC 2.

    UPDATE: THe class i'm writing needs to extend the System.ComponentModel.DataAnnotations namespace. In .NET 4 there is a IValidateObject interface that you can implement, that makes this sort of thing an absolute doddle, but sadly i can't use .Net 4. How do i go about doing the same thing in .Net 3.5?

  • MrBliz
    MrBliz over 13 years
    Hi thanks, after reading you answer i realised i needed to provide my info. Of course the code that you have provided will validate a date, but it wasn't that part of the problem i was stuck on. I needed to know what interfaces to implement to extend the dataannotations namespace. Thanks anyway.
  • MrBliz
    MrBliz over 13 years
    In this case how do i pick up the values for StartDate and EndDate from the model, since they are both user entered values?
  • just.jimmy
    just.jimmy over 13 years
    Changed my answer. :) So StartDate checks with DateTime.Now. EndDate checks with StartDate which is user entered to make sure it's after the start date.
  • DanO
    DanO almost 12 years
    Definitely a better solution! +1 for the helpful link!
  • Azarsa
    Azarsa over 9 years
    Why my dateStartString from current context is null?
  • matty_simms
    matty_simms almost 5 years
    Here is the entry from the wayback machine. web.archive.org/web/20150204084444/http://www.a2zdotnet.com/‌​…
  • Chris
    Chris over 3 years
    Welcome to Stack Overflow. Code dumps without any explanation are rarely helpful. Stack Overflow is about learning, not providing snippets to blindly copy and paste. Please edit your question and explain how it works better than what the OP provided. See How to Answer.