在同一属性上重复相同的DataAnnotation属性

时间:2011-11-04 20:13:29

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

我正在进行一些非常疯狂的自定义验证。基本上,根据下拉列表的选择,将确定针对目标属性验证的值。

例如,我有以下下拉列表:

  

1 =车辆   2 =卡车

在我的自定义验证中,如果选择是汽车,那么该值不能超过20.如果选择是卡车,则值不能超过40。

所以我的属性需要看起来像这样:

[ValueBelowIf("1", 20)]
[ValueBelowIf("2", 40)]
public int Value { get; set; }

当然,要编译它,我必须在我的自定义属性上设置它:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class ValueBelowIfAttribute : ValidationAttribute, IClientValidatable

但是,似乎只有第一个属性被绑定 - 第二个属性被忽略。

我做错了什么?

3 个答案:

答案 0 :(得分:1)

您需要覆盖TypeId的默认实现。 MVC的验证器将仅根据它的TypeId值评估每个唯一属性。

将您的属性实现更改为以下内容,它将起作用:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class ValueBelowIfAttribute : ValidationAttribute, IClientValidatable
{
  private object _typeId = new object();
  public override object TypeId
  {
    get { return this._typeId; }
  }
  // OTHER CODE
}

从我收集的内容来看,AllowMultiple,至少在MVC的情况下,只是告诉编译器该属性有效出现多次,但是TypeId控制着如何在运行时评估这些属性。

这可能很有用,因为您可以静态地(在编译时)允许多次应用相同的属性类型,但在运行时忽略逻辑上重复的属性。例如,在我的示例中,我可以返回属性参数的哈希码,而不是返回保证唯一的新对象()。在这种情况下,如果您这样做:

[ValueBelowIf("1", 20)]
[ValueBelowIf("2", 40)]
[ValueBelowIf("2", 40)]
public int Value { get; set; }

第二个[ValueBelowIf("2", 40)]将不会被评估。

详细了解我在哪里找到答案: http://www.paraesthesia.com/archive/2010/03/02/the-importance-of-typeid-in-asp.net-mvc-dataannotations-validation-attributes.aspx

答案 1 :(得分:0)

您正在尝试将类范围的验证逻辑实现为属性验证技术。不要那样做!使用适当的类验证机制,例如实现 IValidatableObject ,或使用 FluentValidation

答案 2 :(得分:0)

由于C#Attrbiutes是有限的常量,我发现实现此目的的最佳方法是通过构造函数提供所有值作为单独的值。这很难看,但这是唯一可行的方法。

例如:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class ValueBelowIfAttribute : ValidationAttribute, IClientValidatable
{
    public string IfValue { get; set; }
    public int BelowValue { get; set; }
    public string IfValue2 { get; set; }
    public int BelowValue2 { get; set; }
    public string IfValue3 { get; set; }
    public int BelowValue3 { get; set; }

    public ValueBelowIfAttribute(string ifValue, int belowValue)
    {
        // do stuff
    }

    public ValueBelowIfAttribute(string ifValue, int belowValue, string ifValue2, int belowValue2)
    {
        // do stuff
    }

    public ValueBelowIfAttribute(string ifValue, int belowValue, string ifValue2, int belowValue2, string ifValue3, int belowValue3)
    {
        // do stuff
    }
}