DataAnnotation attributes buddy class strangeness - ASP.NET MVC

Posted by JK on Stack Overflow See other posts from Stack Overflow or by JK
Published on 2010-05-27T02:10:12Z Indexed on 2010/05/27 2:11 UTC
Read the original article Hit count: 307

Given this POCO class that was automatically generated by an EntityFramework T4 template (has not and can not be manually edited in any way):

public partial class Customer
{
    [Required]
    [StringLength(20, ErrorMessage = "Customer Number - Please enter no more than 20 characters.")]
    [DisplayName("Customer Number")]
    public virtual string CustomerNumber { get;set; }

    [Required]
    [StringLength(10, ErrorMessage = "ACNumber - Please enter no more than 10 characters.")]
    [DisplayName("ACNumber")]
    public virtual string ACNumber{ get;set; }
}

Note that "ACNumber" is a badly named database field, so the autogenerator is unable to generate the correct display name and error message which should be "Account Number".

So we manually create this buddy class to add custom attributes that could not be automatically generated:

[MetadataType(typeof(CustomerAnnotations))]
public partial class Customer { }

public class CustomerAnnotations
{
    [NumberCode] // This line does not work
    public virtual string CustomerNumber { get;set; }

    [StringLength(10, ErrorMessage = "Account Number - Please enter no more than 10 characters.")]
    [DisplayName("Account Number")]
    public virtual string ACNumber { get;set; }
}

Where [NumberCode] is a simple regex based attribute that allows only digits and hyphens:

[AttributeUsage(AttributeTargets.Property)]
public class NumberCodeAttribute: RegularExpressionAttribute
{
    private const string REGX = @"^[0-9-]+$"; 
    public NumberCodeAttribute() : base(REGX) { }
}

NOW, when I load the page, the DisplayName attribute works correctly - it shows the display name from the buddy class not the generated class.

The StringLength attribute does not work correctly - it shows the error message from the generated class ("ACNumber" instead of "Account Number").

BUT the [NumberCode] attribute in the buddy class does not even get applied to the AccountNumber property:

foreach (ValidationAttribute attrib in prop.Attributes.OfType<ValidationAttribute>())
{
    // This collection correctly contains all the [Required], [StringLength] attributes
    // BUT does not contain the [NumberCode] attribute
    ApplyValidation(generator, attrib);
}

Why does the prop.Attributes.OfType<ValidationAttribute>() collection not contain the [NumberCode] attribute? NumberCode inherits RegularExpressionAttribute which inherits ValidationAttribute so it should be there.

If I manually move the [NumberCode] attribute to the autogenerated class, then it is included in the prop.Attributes.OfType<ValidationAttribute>() collection.

So what I don't understand is why this particular attribute does not work in when in the buddy class, when other attributes in the buddy class do work. And why this attribute works in the autogenerated class, but not in the buddy. Any ideas?

Also why does DisplayName get overriden by the buddy, when StringLength does not?

© Stack Overflow or respective owner

Related posts about c#

Related posts about asp.net-mvc