Data Annotation Ranges of Dates

后端 未结 7 1341
故里飘歌
故里飘歌 2020-12-08 18:53

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

something like

[Range(typeof(DateTime), DateTime.MinValue.ToString(), DateTime.To         


        
相关标签:
7条回答
  • 2020-12-08 18:55

    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}")]
    
    0 讨论(0)
  • 2020-12-08 19:02

    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 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.

    0 讨论(0)
  • 2020-12-08 19:04

    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);
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-08 19:07

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

    0 讨论(0)
  • 2020-12-08 19:13

    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;}
    
    0 讨论(0)
  • 2020-12-08 19:18

    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()) { } 
       }
    
    0 讨论(0)
提交回复
热议问题