DataAnnotation attributes buddy class strangeness

2020-07-17 16:10发布

问题:

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?

回答1:

I noticed that your NumberCodeAttribute doesn't specify AllowMultiple=True in the AttributeUsage attribute. The default for that parameter (if it isn't specified) is false. Try adding that on and it should appear.



回答2:

I recreated your code using VS2008 and MVC2 and it worked fine for me.