为什么ASP.Net MVC范围属性采用Type?

时间:2011-03-20 03:15:37

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

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

我正在尝试做的是找到一种简单的方法来验证一个3字符串,该字符串必须存在于枚举,任何sugestions?

谢谢, 亚历克斯。

6 个答案:

答案 0 :(得分:17)

我确实找到了你提到的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")]

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

enter image description here

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

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

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

但等等......

只需删除客户端验证!我删除了对JQuery验证和Unobtrusive验证和中提琴的引用!它完美无缺。 发布,然后正确显示错误当值(字符和日期)都不在指定范围内时。

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

希望这有用。

答案 1 :(得分:4)

我还注意到jQuery Validation与ASP MVC Range-validator不兼容(似乎jQuery Validation插件需要将范围值作为数字)。

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

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

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

答案 2 :(得分: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; }
}

DateRange只是:

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);
    }
}

答案 3 :(得分:3)

我也很晚才接受这个:)

当然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);
    }
}

答案 4 :(得分:1)

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

<强> CustomDateRange

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);
    }
}
}

ClientSide Integration

(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下载完整的实施。

答案 5 :(得分:-3)

专家!这是另一个问题。 我在这里找到了: 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/