Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The same DataAnnotation attribute repeated on the same property

I have some pretty crazy custom validation I'm working on. Basically, based on the selection of a dropdown, that will determine what values are validated against the target property.

For example, I have the following dropdown:

1 = Car
2 = Truck

On my custom validation, if the selection is car, then the value can't be more than 20. If the selection is truck, the value can't be more than 40.

So my attributes need to look something like this:

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

Of course, to even get it to compile, I have to set this on my custom attribute:

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

However, it appears only the first attribute is being bound -- the second is ignored.

What am I doing wrong?

like image 304
Jerad Rose Avatar asked Apr 25 '26 05:04

Jerad Rose


1 Answers

You need to override the default implementation of TypeId. MVC's validator will only evaluate each unique attribute based on it's TypeId value.

Change your attribute implementation to the following, and it'll work:

[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
}

From what I gather, AllowMultiple, at least in the case of MVC, just tells the compiler that the attribute is valid appearing multiple times, but it is TypeId that controls how those attributes are evaluated at runtime.

This can be useful because you can statically (at compile time) allow the same attribute type to be applied multiple times, but at runtime ignore logically duplicated attributes. For example, in my example instead of returning a guaranteed-unique new object(), I could return a hashcode of the attribute parameters. In that case, if you did:

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

the second [ValueBelowIf("2", 40)] would not be evaluated.

Read more details where I came across the answer here: http://www.paraesthesia.com/archive/2010/03/02/the-importance-of-typeid-in-asp.net-mvc-dataannotations-validation-attributes.aspx

like image 189
bojingo Avatar answered Apr 27 '26 12:04

bojingo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!