范围属性使用动态值而不是固定

时间:2014-03-07 17:36:40

标签: c# .net asp.net-mvc

我想在我的mvc viewmodel中使用Data annotations Range属性。问题是这个范围属性应该是动态值。

我的viewmodel还有ValueOne和ValueTwo属性。根据这个值,我想设置Range attr。像

这样的价值观
 [Range(1, 1000, ErrorMessage = "Value for {0} must be between {1} and {2}.")]

其中1和1000应替换为ValueOne和ValueTwo属性值。

所以我尝试使用自定义ValidateCustomAttribute

public class ValidateCustomAttribute: ValidationAttribute
    {
        private readonly double _MinValue = 0;
        private readonly double _MaxValue = 100;

        public override bool IsValid(object value)
        {
            double val = (double)value;
            return val >= _MinValue && val <= _MaxValue;
        }

        public override string FormatErrorMessage(string name)
        {
            return string.Format(ErrorMessage, _MinValue, _MaxValue);
        }
    }

我该如何替换

private readonly double _MinValue = 0;
private readonly double _MaxValue = 100;

使用动态值(来自我的viewmodel的ValueOne和ValueTwo)。

3 个答案:

答案 0 :(得分:4)

这不能做,你不能在属性中有变量。必须在编译时知道属性值。

请参阅此question/answerthis一个。

答案 1 :(得分:2)

只需添加一个构造函数:

private double _MinValue, _MaxValue; // no readonly keyword

public ValidateCustomAttribute(double min, double max, Func<string> errorMessageAccessor)
    : base(errorMessageAccessor)
{
    _MinValue = min;
    _MaxValue = max;
}

你不能做的是在属性构造函数invokation中有变量。

这是不可能的:

[ValidateCustom(min, max)]

但是如果你在代码中使用文字(或常量),你可以使用:

[ValidateCustom(1, 1000)]

另一个班级或方法:

[ValidateCustom(3, 45)]

您缺少的是构造函数接收这些静态值并将它们附加到您使用属性描述的构造中。


编辑:这个丑陋的方式

如果你真的需要这个,你可以规避限制,但它可以得到它的丑陋。我强烈反对这一点,但你要求它......

  1. 对数据进行分类
  2. 将类别映射到绑定符号
  3. 使用绑定符号
  4. 将绑定符号解析为数据
  5. 所以,让我们开始工作:

    1)对数据进行分类

    说,你的数据是一个范围(min, max),首先要确定哪些值是可能的,假设你有4个可能的范围(可能是数百个,但这完全是另一个问题)。

    (1, 1000)
    (10, 20)
    (3, 45)
    (5, 7)
    

    2)将类别映射到绑定符号

    现在,您必须为这些范围使用enum作为绑定符号:

    public enum MyRanges
    {
        R1, R2, R3, R4
    }
    

    3)使用绑定符号

    将构造函数定义为接受绑定符号:

    private MyRanges _R;
    
    public ValidateCustomAttribute(MyRanges r, Func<string> errorMessageAccessor)
        : base(errorMessageAccessor)
    {
        _R = r;
    }
    

    该属性将使用如下:

    [ValidateCustom(MyRanges.R2, "ERROR!")]
    

    4)将绑定符号解析为数据

    您需要的最后一个是包含实际数据的字典:

    Dictionary<MyRanges, double> dataMin = {
        { MyRanges.R1, 1},
        { MyRanges.R2, 10},
        { MyRanges.R3, 3},
        { MyRanges.R4, 5}
    };
    
    Dictionary<MyRanges, double> dataMax = {
        { MyRanges.R1, 1000},
        { MyRanges.R2, 20},
        { MyRanges.R3, 45},
        { MyRanges.R4, 7}
    };
    

    测试将以这种方式使用绑定:

    public override bool IsValid(object value)
    {
        double val = (double)value;
        return val >= dataMin[_R] && val <= dataMax[_R]; // get data through binding
    }
    

    现在您可以在幕后更改 这些值,并且绑定符号绑定的所有属性的行为都不同:

    dataMax[MyRanges.R4] = 29;
    

    完成。

    现在无法更改的是从属性到类别的绑定,但类别中包含的数据可以自由更改。

    但丑陋且无法维持。不要这样做,真的。

答案 2 :(得分:0)

你可以这样做:

public class MinimumAgeAttribute : RangeAttribute
{
    public static string MinimumValue => ConfigurationManager.AppSettings["your key"];
    public static string MaxValue => ConfigurationManager.AppSettings["your key"];

    public CustomRangeAttribute(Type type):base(type,MaxValue , MinimumValue)
    {
    }

}

在此之后你必须在Global.asax中注册属性,如下所示:

DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(CustomRangeAttribute),
            typeof(RangeAttributeAdapter));

在此之后你可以像这样使用它:

[CustomRange(typeof(DateTime), ErrorMessage = "You message")]
public DateTime DateOfBirth { get; set; }