【问题标题】:why does ASP.Net MVC Range Attribute take a Type?为什么 ASP.Net MVC 范围属性采用类型?
【发布时间】:2011-03-20 03:15:37
【问题描述】:

我只是想知道为什么 Range 验证属性可以将一个 Type 和两个字符串作为参数?这是针对 Enum 或类似的东西验证字符串吗?

另外我想做的是找到一种简单的方法来验证必须存在于枚举中的 3 个字符串,有什么建议吗?

谢谢, 亚历克斯。

【问题讨论】:

  • 3 个字符的字符串如何/为什么需要在枚举中?
  • 我试图将地址状态存储为 3 个字符的字符串,但我现在将其更改为一个字节,并且正在编辑数据类型以匹配枚举的数据类型。
  • 看我的回答。不确定枚举如何工作,但如果您知道 string.Compare() 如何比较它们,则 3 char 字符串可以工作。此外,此验证仅适用于服务器端。您可以添加自己的自定义类,为您的字符串实现 IComparable
  • 另请注意:RangeAttribute 来自 System.ComponentModel.DataAnnotations.dll 不是 asp.net mvc 的一部分。

标签: c# asp.net-mvc asp.net-mvc-3 data-annotations


【解决方案1】:

我确实发现你提到的 Range ctor 有问题。忍不住调查了一下。 (所以我在调查时像写日志一样写了这个答案。)

来自MSDN

public RangeAttribute(
    Type type,
    string minimum,
    string maximum
)

注意:MSDN 说Type 应该是IComparable。而且,他们的示例描述说它不是用于日期比较!。

因此,由于我打开了我的生产 asp.net mvc3 应用程序,因此我在日期时间如下所示:

[Range(typeof(DateTime),"1-Jan-1910","1-Jan-2060")]

当我运行它时会发生这种情况:

请注意,虽然我用虚线和没有时间指定了最小值和最大值,但它给出了不同的格式,所以它可能是 TryParsing 字符串,对吧?但我敢肯定它不可能ICompare 客户端的两个!?现在无论我输入什么日期仍然显示错误。 (日期输入为 20 年 3 月 11 日(2020 年为 20 日)。

我尝试了 char(如下),因为那也是 IComparable。一样。它实际上无法在客户端进行范围比较。

[Range(typeof(char), "a", "g")]

但是等等……

只需删除客户端验证!我删除了对 JQuery 验证和不显眼验证和中提琴的引用!它工作完美。它发布,然后当值(Char 和 Date)不在指定范围内时正确显示错误

注意:也许有人可以将此解决方案扩展为仅禁用某些字段以进行客户端验证。

希望这对您有所帮助。

【讨论】:

  • @alex 欢迎您。我实际上虽然它直到 but wait 才起作用,那是我尝试禁用客户端验证并且它起作用的时候! =P
  • @gideon:我知道这是很久以前发布的,但仍然:非常感谢您的明确解释!我今天遇到了这个问题,找不到合适的解释.. :)
  • 您不必完全禁用客户端验证。您可以改为删除特定文本框的客户端范围验证。像这样:$('yourTextBox').rules('remove','range');
  • 它不接受“20”,因为它读作“0020”,而不是“2020”。由于 Y2K 错误,两位数的年份不再与代码中的许多内容兼容。
【解决方案2】:

我还注意到 jQuery Validation 不能很好地与 ASP MVC Range-validator 配合使用(似乎 jQuery Validation 插件要求范围值是数字)。

一个简单的解决方案是关闭特定字段的验证。无论如何,服务器端验证都会起作用。

以下示例将从所有具有“日期”类的输入字段中删除“范围”规则:

$('input.date').each(function() {
    $(this).rules('remove', 'range');
});

【讨论】:

    【解决方案3】:

    我最终创建了一个自定义 DateRangeAttribute,如 here 所述。 您没有获得客户端验证,但您可以自定义它以满足您的需求,并且不需要使用 javascript。这是代码以及如何使用它:

    public class Person
    {
        [Required]
        public string FirstName { get; set; }
    
        [DataType(DataType.Date)]
        [DateRange("2010/12/01", "2010/12/16")]
        public DateTime DateOfBirth { get; set; }
    }
    

    日期范围很简单:

    public class DateRangeAttribute : 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 DateRangeAttribute(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);
        }
    }
    

    【讨论】:

      【解决方案4】:

      我也很晚才知道这一点:)

      CustomValidation 属性肯定是为这些情况而构建的吗?

      这样我们就不必去改变任何客户端验证。此外,它的优势在于它让我们有机会应用可配置的范围。

      例如:

      public class Person
      {
          [CustomValidation(typeof(Person), "validateDOB")]
          public DateTime DateOfBirth { get; set; }
      
          //field (or property) limits that we could look-up
          private static DateTime _MinDate = new DateTime(1, 1, 1900);
          private static DateTime _MaxDate = new DateTime(31, 12, 2999);
      
          //this method must be public and static and take a single
          //parameter: the field to validate
          public static ValidationResult validateDOB(DateTime dateOfBirth)
          {
              string errorMsg = "";
              if (dateOfBirth < _MinDate)
              {
                  errorMsg = "Date too early";
              }
              else if (dateOfBirth > _MaxDate)
              {
                  errorMsg = "Date too late";
              }
              return errorMsg == "" ? null : new ValidationResult(errorMsg);
          }
      }
      

      【讨论】:

        【解决方案5】:

        您可以使用以下自定义日期范围验证,它将日期值与提供的最小和最大日期或提到的相关属性进行比较。它还演示了客户端验证支持和集成。

        自定义日期范围

        public enum CustomDateRangeType
        {
        /// <summary>
        /// The direct value of property.
        /// </summary>
        Value,
        
        /// <summary>
        /// The dependent property.
        /// </summary>
        DependentProperty
        }
        
        /// <summary>
        /// The CustomDateComparAttribute Validator
        /// </summary>
        [AttributeUsage(AttributeTargets.All | AttributeTargets.Property,        AllowMultiple = false, Inherited = true)]
         public sealed class CustomDateRangeAttribute : ValidationAttribute,  IClientValidatable
         {
        
        private const string UniversalDatePattern = "yyyy-M-d";
        
        /// <summary>
        /// The min date.
        /// </summary>
        private string minDate;
        
        /// <summary>
        /// The max date.
        /// </summary>
        private string maxDate;
        
        /// <summary>
        /// The date range type
        /// </summary>
        private CustomDateRangeType dateRangeType;
        
        /// <summary>
        /// Initializes a new instance of the <see cref="CustomDateRangeAttribute"/> class.
        /// </summary>
        /// <param name="minDate">
        /// The min date in <example>yyyy-M-d</example> format. Throws FormatException exception if not provided in specified format.
        /// </param>
        /// <param name="maxDate">
        /// max date in <example>yyyy-M-d</example> format. Throws FormatException exception if not provided in specified format.
        /// </param>
        public CustomDateRangeAttribute(string minDate, string maxDate)
            : this(CustomDateRangeType.Value, minDate, maxDate)
        {
        }
        
        /// <summary>
        /// Initializes a new instance of the <see cref="CustomDateRangeAttribute" /> class.
        /// </summary>
        /// <param name="dateRangeType">Type of the date range.</param>
        /// <param name="minDate">The minimum date dependent property or value. If value then it should be <example>yyyy-M-d</example> format.</param>
        /// <param name="maxDate">The maximum date property or value. If value then it should be <example>yyyy-M-d</example> format.</param>
        public CustomDateRangeAttribute(CustomDateRangeType dateRangeType, string minDate, string maxDate)
        {
            if (dateRangeType == CustomDateRangeType.Value)
            {
                if (!IsValidDate(minDate))
                {
                    throw new FormatException(string.Format(CultureInfo.InvariantCulture, "Max date should be in {0} format.", UniversalDatePattern));
                }
        
                if (!IsValidDate(maxDate))
                {
                    throw new FormatException(string.Format(CultureInfo.InvariantCulture, "Min date should be in {0} format.", UniversalDatePattern));
                }
            }
        
            this.dateRangeType = dateRangeType;
            this.minDate = minDate;
            this.maxDate = maxDate;
        }
        
        /// <summary>
        /// Gets the min date.
        /// </summary>
        public string MinDate
        {
            get
            {
                return this.minDate;
            }
        }
        
        /// <summary>
        /// Gets the max date.
        /// </summary>
        public string MaxDate
        {
            get
            {
                return this.maxDate;
            }
        }
        
        /// <summary>
        /// Gets the type of the date range.
        /// </summary>
        /// <value>
        /// The type of the date range.
        /// </value>
        public CustomDateRangeType DateRangeType
        {
            get
            {
                return this.dateRangeType;
            }
        }
        
        /// <summary>
        /// gets client validation rules
        /// </summary>
        /// <param name="metadata">
        /// meta data parameter
        /// </param>
        /// <param name="context">
        /// controller context
        /// </param>
        /// <returns>
        /// client validation rule
        /// </returns>
        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(
            ModelMetadata metadata,
            ControllerContext context)
        {
            if (metadata != null)
            {
                return new[]
                           {
                               new ModelClientValidationCustomDateRangeRule(
                                   this.ErrorMessageString,
                                   this.DateRangeType,
                                   this.MinDate,
                                   metadata.PropertyName,
                                   this.MaxDate)
                           };
            }
        
            return null;
        }
        
        /// <summary>
        /// overridden method
        /// </summary>
        /// <param name="value">
        /// value to be compared
        /// </param>
        /// <param name="validationContext">
        /// validation context
        /// </param>
        /// <returns>
        /// validation result
        /// </returns>
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var result = ValidationResult.Success;
            var errorResult = new ValidationResult(this.ErrorMessageString);
            if (value == null)
            {
                return result;
            }
        
            DateTime dateValue = (DateTime)value;
        
            if (this.DateRangeType == CustomDateRangeType.Value)
            {
                if (ParseDate(this.MinDate) <= dateValue && dateValue <= ParseDate(this.MaxDate))
                {
                    return result;
                }
            }
            else
            {
                if (validationContext == null || string.IsNullOrEmpty(this.MinDate) || string.IsNullOrEmpty(this.MaxDate))
                {
                    return errorResult;
                }
        
                var minDatePropertyInfo = validationContext.ObjectType.GetProperty(this.MinDate);
                var maxDatePropertyInfo = validationContext.ObjectType.GetProperty(this.MaxDate);
                if (minDatePropertyInfo == null || maxDatePropertyInfo == null)
                {
                    return errorResult;
                }
        
                var minDateValue = Convert.ToDateTime(
                    minDatePropertyInfo.GetValue(validationContext.ObjectInstance, null), 
                    CultureInfo.CurrentCulture);
                var maxDateValue = Convert.ToDateTime(maxDatePropertyInfo.GetValue(validationContext.ObjectInstance, null), 
                    CultureInfo.CurrentCulture);
        
                if (minDateValue <= dateValue && dateValue <= maxDateValue)
                {
                    return result;
                }
            }
        
            return errorResult;
        }
        
        /// <summary>
        /// The parse date.
        /// </summary>
        /// <param name="dateValue">
        /// The date value.
        /// </param>
        /// <returns>
        /// The <see cref="DateTime"/>.
        /// </returns>
        private static DateTime ParseDate(string dateValue)
        {
            return DateTime.ParseExact(
                dateValue, UniversalDatePattern, 
                CultureInfo.InvariantCulture);
        }
        
        /// <summary>
        /// The is valid date.
        /// </summary>
        /// <param name="dateValue">
        /// The date value.
        /// </param>
        /// <returns>
        /// A value indicating whether the provided dateValue is a valid date.
        /// </returns>
        private static bool IsValidDate(string dateValue)
        {
            DateTime? date = null;
            var regex = new Regex(@"\d{4}-\d{1,2}-\d{1,2}");
            if (regex.IsMatch(dateValue))
            {
                var dateParts = dateValue.Split('-');
                if (dateParts.Length == 3)
                {
                    date = new DateTime(
                        Convert.ToInt32(dateParts[0], CultureInfo.InvariantCulture),
                        Convert.ToInt32(dateParts[1], CultureInfo.InvariantCulture),
                        Convert.ToInt32(dateParts[2], CultureInfo.InvariantCulture));
                }
            }
        
            return date != null;
        }
        
        /// <summary>
        ///     ModelClientValidationCustomCompareRule class
        /// </summary>
        private class ModelClientValidationCustomDateRangeRule : ModelClientValidationRule
        {
            /// <summary>
            /// Initializes a new instance of the <see cref="ModelClientValidationCustomDateRangeRule"/> class.
            /// </summary>
            /// <param name="errorMessage">error message</param>
            /// <param name="dateRangeType">Type of the date range.</param>
            /// <param name="minDateProperty">The minimum date property.</param>
            /// <param name="currentProperty">The current property.</param>
            /// <param name="maxDateProperty">The maximum date property.</param>
            public ModelClientValidationCustomDateRangeRule(
                string errorMessage,
                CustomDateRangeType dateRangeType,
                string minDateProperty,
                string currentProperty,
                string maxDateProperty)
            {
                this.ErrorMessage = errorMessage;
                this.ValidationType = "customdaterange";
                this.ValidationParameters.Add("daterangetypeproperty", dateRangeType.ToString());
                this.ValidationParameters.Add("mindateproperty", minDateProperty);
                this.ValidationParameters.Add("currentproperty", currentProperty);
                this.ValidationParameters.Add("maxdateproperty", maxDateProperty);
            }
        }
        }
        

        客户端集成

        (function ($) {
        jQuery.validator.addMethod('customdaterange', function (value, element, param) {
            if (value == '' || value == undefined) {
                return true;
            }
        
            var minValue;
            var maxValue;
        
            if (param.daterangetypeproperty == "DependentProperty") {
                var minDateValue = $('#' + param.mindateproperty).val();
                var maxDateValue = $('#' + param.maxdateproperty).val();
                minValue = new Date(minDateValue);
                maxValue = new Date(maxDateValue);
            } else {
                minValue = new Date(param.mindateproperty);
                maxValue = new Date(param.maxdateproperty);
            }
        
            var currentValue = new Date(value);
            if (minValue <= currentValue && currentValue <= maxValue) {
                return true;
            }
        
            return false;
        });
        
        jQuery.validator.unobtrusive.adapters.add('customdaterange', ['daterangetypeproperty', 'mindateproperty', 'currentproperty', 'maxdateproperty'], function (options) {
            var params = {
                daterangetypeproperty: options.params.daterangetypeproperty,
                mindateproperty: options.params.mindateproperty,
                currentproperty: options.params.currentproperty,
                maxdateproperty: options.params.maxdateproperty
            };
        
            options.rules['customdaterange'] = params;
            if (options.message) {
                options.messages['customdaterange'] = options.message;
            }
        });
        }(jQuery));
        

        演示

        模型

        public class DateRangeModel
        {
        public DateRangeModel()
        {
            this.MinDateDependentProperty = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);
            this.MaxDateDependentProperty = DateTime.Today.AddDays(1 - DateTime.Today.Day).AddMonths(1);
        }
        
        [Required]
        [CustomDateRange("2015-10-01", "2015-10-15", ErrorMessage = "Date value is not in range.")]
        [DataType(DataType.Date)]
        public DateTime DateCompareWithMinMaxValue { get; set; }
        
        [Required]
        [CustomDateRange(CustomDateRangeType.DependentProperty, "MinDateDependentProperty", "MaxDateDependentProperty", 
            ErrorMessage = "Date to select value is not in range.")]
        [DataType(DataType.Date)]
        public DateTime DateCompareWithMinMaxDependentProperty { get; set; }
        
        [Required]
        [DataType(DataType.Date)]
        public DateTime MinDateDependentProperty { get; set; }
        
        [Required]
        [DataType(DataType.Date)]
        public DateTime MaxDateDependentProperty { get; set; }
        }
        

        Date controls with validations

        here下载完整的实现。

        【讨论】:

          【解决方案6】:

          伙计们!这是另一种解决方案。 我在这里找到了它: MVC Validation Lower/Higher than other value

          public class FinanceModel{
             public int MinimumCost {get;set;}
          
             [GreaterThan("MinimumCost")]
             public int MaximumCost {get;set;}
          }
          

          http://foolproof.codeplex.com/

          【讨论】:

          • 您所拥有的是设置两个不同的参数并查看一个参数与另一个参数的比较,而不是检查设定范围内的单个参数。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-01-29
          • 1970-01-01
          • 1970-01-01
          • 2021-06-27
          • 1970-01-01
          相关资源
          最近更新 更多