Data Annotation Ranges of Dates

C#asp.net MvcDateModel View-ControllerData Annotations

C# Problem Overview


Is it possible to use [Range] annotation for dates?

something like

[Range(typeof(DateTime), DateTime.MinValue.ToString(), DateTime.Today.ToString())]

C# Solutions


Solution 1 - C#

I did this to fix your problem

 public class DateAttribute : RangeAttribute
   {
      public DateAttribute()
        : base(typeof(DateTime), DateTime.Now.AddYears(-20).ToShortDateString(),     DateTime.Now.AddYears(2).ToShortDateString()) { } 
   }

Solution 2 - C#

Docs on MSDN says you can use the RangeAttribute

[Range(typeof(DateTime), "1/2/2004", "3/4/2004",
        ErrorMessage = "Value for {0} must be between {1} and {2}")]
public datetime Something { get; set;}

Solution 3 - C#

jQuery validation does not work with [Range(typeof(DateTime),"date1","date2"] -- My MSDN doc is incorrect

Solution 4 - C#

Here is another solution.

[Required(ErrorMessage = "Date Of Birth is Required")]
[DataType(DataType.Date, ErrorMessage ="Invalid Date Format")]
[Remote("IsValidDateOfBirth", "Validation", HttpMethod = "POST", ErrorMessage = "Please provide a valid date of birth.")]
[Display(Name ="Date of Birth")]
public DateTime DOB{ get; set; }

The simply create a new MVC controller called ValidationController and past this code in there. The nice thing about the "Remote" approach is you can leverage this framework to handle any kind of validations based on your custom logic.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Mail;
using System.Web;
using System.Web.Mvc;

namespace YOURNAMESPACEHERE
{
    public class ValidationController : Controller
    {
        [HttpPost]
        public JsonResult IsValidDateOfBirth(string dob)
        {
            var min = DateTime.Now.AddYears(-21);
            var max = DateTime.Now.AddYears(-110);
            var msg = string.Format("Please enter a value between {0:MM/dd/yyyy} and {1:MM/dd/yyyy}", max,min );
            try
            {
                var date = DateTime.Parse(dob);
                if(date > min || date < max)
                    return Json(msg);
                else
                    return Json(true);
            }
            catch (Exception)
            {
                return Json(msg);
            }
        }
    }
}

Solution 5 - C#

For those rare occurrences when you are forced to write a date as a string (when using attributes), I highly recommend using the ISO-8601 notation. That eliminates any confusion as to whether 01/02/2004 is january 2nd or february 1st.

[Range(typeof(DateTime), "2004-12-01", "2004-12-31",
    ErrorMessage = "Value for {0} must be between {1} and {2}")]
public datetime Something { get; set;}

Solution 6 - C#

I use this approach:

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
internal sealed class DateRangeAttribute : ValidationAttribute
{
    public DateTime Minimum { get; }
    public DateTime Maximum { get; }

    public DateRangeAttribute(string minimum = null, string maximum = null, string format = null)
    {
        format = format ?? @"yyyy-MM-dd'T'HH:mm:ss.FFFK"; //iso8601

        Minimum = minimum == null ? DateTime.MinValue : DateTime.ParseExact(minimum, new[] { format }, CultureInfo.InvariantCulture, DateTimeStyles.None); //0 invariantculture
        Maximum = maximum == null ? DateTime.MaxValue : DateTime.ParseExact(maximum, new[] { format }, CultureInfo.InvariantCulture, DateTimeStyles.None); //0 invariantculture

        if (Minimum > Maximum)
            throw new InvalidOperationException($"Specified max-date '{maximum}' is less than the specified min-date '{minimum}'");
    }
    //0 the sole reason for employing this custom validator instead of the mere rangevalidator is that we wanted to apply invariantculture to the parsing instead of
    //  using currentculture like the range attribute does    this is immensely important in order for us to be able to dodge nasty hiccups in production environments

    public override bool IsValid(object value)
    {
        if (value == null) //0 null
            return true;

        var s = value as string;
        if (s != null && string.IsNullOrEmpty(s)) //0 null
            return true;

        var min = (IComparable)Minimum;
        var max = (IComparable)Maximum;
        return min.CompareTo(value) <= 0 && max.CompareTo(value) >= 0;
    }
    //0 null values should be handled with the required attribute

    public override string FormatErrorMessage(string name) => string.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, Minimum, Maximum);
}

And use it like so:

[DateRange("2004-12-01", "2004-12-2", "yyyy-M-d")]
ErrorMessage = "Value for {0} must be between {1} and {2}")]

Solution 7 - C#

I found issues with the [Range(typeof(DateTime)] annotation and would describe it as "clunky at best" it leaves too much to chance IF it works.

Remote validation seems to be a good way of: avoiding javascript in views and maintaining server side code integrity, personally never like sending code to a client to execute if I can avoid it.

Using @StackThis answer as a base and reference to an [article][1] on remote validation in MVC3

Model

public class SomeDateModel
{
    public int MinYears = 18;
    public int MaxYears = 110;

    [Display(Name = "Date of birth", Prompt = "e.g. 01/01/1900")]
    [Remote(action: "ValidateDateBetweenYearsFromNow", controller: "Validation", areaReference: AreaReference.UseRoot, AdditionalFields = "MinYears,MaxYears", HttpMethod = "GET" ,ErrorMessage = "Subject must be over 18")]
    public DateTime? DOB { get; set; }
}

Controller - Deployed at the root directory

namespace Controllers
{
    public class ValidationController : Controller
    {
        [HttpGet]
        [ActionName("ValidateDateBetweenYearsFromNow")]
        public JsonResult ValidateDateBetweenYearsFromNow_Get()
        {
            //This method expects 3 parameters, they're anonymously declared through the Request Querystring,
            //Ensure the order of params is:
            //[0] DateTime
            //[1] Int Minmum Years Ago e.g. for 18 years from today this would be 18
            //[2] int Maximum Years Ago e.g. for 100 years from today this would be 100
            var msg = string.Format("An error occured checking the Date field validity");
            try
            {
                int MinYears = int.Parse(Request.QueryString[1]);
                int MaxYears = int.Parse(Request.QueryString[2]);

                //Use (0 - x) to invert the positive int to a negative.
                var min = DateTime.Now.AddYears((0-MinYears));
                var max = DateTime.Now.AddYears((0-MaxYears));
                
                //reset the response error msg now all parsing and assignmenst succeeded.
                msg = string.Format("Please enter a value between {0:dd/MM/yyyy} and {1:dd/MM/yyyy}", max, min);
                var date = DateTime.Parse(Request.QueryString[0]);
                if (date > min || date < max)
                    //switch the return value here from "msg" to "false" as a bool to use the MODEL error message
                    return Json(msg, JsonRequestBehavior.AllowGet);
                else
                    return Json(true, JsonRequestBehavior.AllowGet);
            }
            catch (Exception)
            {
                return Json(msg, JsonRequestBehavior.AllowGet);
            }
        }
    }
}

The msg variable is displayed as part of the Html helper ValidationSummary or the Html helper ValidationFor(x=>x.DATETIME)

View

It's important to note that the fields passed as parameter 2 and 3 must exist in the view in order for the remote validation to pass the values to the controller:

    @Html.EditorFor(m => m.DOB)
    @Html.HiddenFor(m => m.MinYears)
    @Html.HiddenFor(m => m.MaxYears)
    @Html.ValidationSummary()

The model and Html helpers will do all the jquery work for you. [1]: http://www.aaronstannard.com/remote-validation-asp-net-mvc3/

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDavyView Question on Stackoverflow
Solution 1 - C#MarkKGreenwayView Answer on Stackoverflow
Solution 2 - C#Daniel ElliottView Answer on Stackoverflow
Solution 3 - C#RickAndMSFTView Answer on Stackoverflow
Solution 4 - C#StackThisView Answer on Stackoverflow
Solution 5 - C#TikallView Answer on Stackoverflow
Solution 6 - C#XDSView Answer on Stackoverflow
Solution 7 - C#RichardView Answer on Stackoverflow