0

I have an EntityFramework model with attributes, which I use to validate the fields.

private person tipProvider;
[Required]
[ForeignKey("TipProviderId")]
public virtual person TipProvider
{
    get { return tipProvider; }
    set
    {
        tipProvider = value;
        ValidateProperty(MethodBase.GetCurrentMethod().Name.Replace("set_", ""));
        raisePropertyChanged(MethodBase.GetCurrentMethod().Name.Replace("set_", ""));
    }
}

I get the PropertyInfo and then its validation attributes, which I use to validate the property:

public virtual void ValidateProperty(string property)
{
    errors[property].Clear();
    var propertyInfo = this.GetType().GetProperty(property);
    var propertyValue = propertyInfo.GetValue(this);
    var validationAttributes = propertyInfo.GetCustomAttributes(true).OfType<ValidationAttribute>();
    foreach (var validationAttribute in validationAttributes)
    {
        if (!validationAttribute.IsValid(propertyValue))
        {
            errors[property].Add(validationAttribute.FormatErrorMessage(string.Empty));
        }
    }
    raiseErrorsChanged(property);
}

When the property is virtual, I cannot find the attributes via reflection. If the virtual keyword is removed, the attributes are found.

I'm really confused by this behavior. Why can't attributes be applied on virtual properties?

Domysee
  • 12,718
  • 10
  • 53
  • 84
  • Try to set the BindingFlags appropiate. Like: `static void Main() { var method = typeof(A).GetMethod("Method", BindingFlags.Public | BindingFlags.Instance); Console.WriteLine(method.IsVirtual); var property = typeof(A).GetProperty("Property", BindingFlags.Public | BindingFlags.Instance); Console.WriteLine(property.GetGetMethod().IsVirtual); } public class A { public virtual void Method() { } public virtual string Property { get; set; } }}` – Frederick Aug 05 '15 at 19:39
  • @Frederick no change, GetGetMethod().IsVirtual and GetSetMethod().IsVirtual are both true – Domysee Aug 05 '15 at 19:51
  • Yes they are. But with the BindingFlags set, you have a valid PropertyInfo object. Isn't this what you're looking for? – Frederick Aug 05 '15 at 19:57
  • @Frederick I had a valid PropertyInfo object before, it is just that I cannot find the attributes through it – Domysee Aug 05 '15 at 20:06
  • Are you overriding the property in a derived class? – Thomas Levesque Aug 05 '15 at 20:22
  • Another try could be, using: `Attribute.GetCustomAttributes(propertyInfo, typeof(ValidationAttribute), true).OfType();` [like](https://stackoverflow.com/questions/2520035/inheritance-of-custom-attributes-on-abstract-properties) I'm sorry this is only guessing and doing searches on my own, cause my first approch works here. – Frederick Aug 05 '15 at 20:32
  • @HansPassant: [RequiredAttribute](https://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.requiredattribute%28v=vs.110%29.aspx) is one – Frederick Aug 05 '15 at 20:34
  • Or you can use [Validator](https://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.validator%28v=vs.110%29.aspx) and [CallerMemberNameAttribute](https://msdn.microsoft.com/de-de/library/system.runtime.compilerservices.callermembernameattribute%28v=vs.110%29.aspx) without Reflection. `private void ValidateProperty(T value, [CallerMemberName] string propertyName = "") { var ctx= new ValidationContext(this, null, null); ctx.MemberName = propertyName; var results = new List(); Validator.TryValidateProperty(value, ctx, results); ...` – Frederick Aug 05 '15 at 20:56

1 Answers1

3

I do not know exactly what are you trying to do, but from what I know from EntityFramework, the problem is not exactly what you are thinking. You CAN apply attributes to virtual properties, and it is possible to recover them via reflection without any problem, just the way you are doing.

But on EF entities, when you mark a property as virtual, you are defining to the EF that the property is a navigation property (a property used to access foreign key data in a relationship, and retrieve it as child Entities).

Then, when you get a new instance of this entity from the database context at runtime, and access that property, EF will create a new class (dynamic proxy) derived from your class and uses it instead of your original class. Entity Framework does it to maintain the concept of "Lazy Loading" your relationships - avoiding loading an entire new dependent entity tree without being needed.

Because EF makes a new class derived from your Entity, AND the property is being overriden by that, your attribute is not being inherited by it.

You can see more about virtual marks and Navigation properties on this post.

Community
  • 1
  • 1
Ismael
  • 622
  • 6
  • 11