On the ASP.NET MVC team, we occasionally get questions about attributes and how they apply from interfaces to classes, like:
I have an interface IFoo defined like this:
public interface IFoo { [Required] string Name { get; set; } }And I have a model class defined like this:
public class ConcreteFoo : IFoo { public string Name { get; set; } }Why doesn't the validation attribute from IFoo.Bar apply to ConcreteFoo.Bar?
The difference between base classes and interfaces in the CLR is responsible for this difference.
Base classes are inherited; that is, any methods, properties, etc., present on the base class are also present in the derived class. Interfaces, on the other hand, are implemented; that is, the class is required to provide implementations of the interface methods, properties, etc. Interface implementation can take two forms: implicit and explicit.
Implicit implementation (as seen above) is when a class implements the method/property in question as a public method or property on the class. It's important to note that this method/property is NOT the same thing as the interface method/property; it merely has the same signature, and thus can be used to implicitly create the implementation of the interface. In reflection terms, the two are distinct and different. Any metadata attached to the interface method or property is not attached to the class method or property, because of this difference.
These are rules set down by the CLR. To relate this to MVC, it's important to understand that MVC's model binding system works based on the type that was requested. This usually means the concrete type, since the action method parameter for models is usually the concrete type (which MVC can implicitly create) and not the interface type (which MVC cannot). Thus, when MVC uses reflection to find validation attributes, it does so using the concrete type: meaning, the type without the attribute applied to it. Since an explicitly implemented interface method/property is private, MVC's model binder would never see them.
The simple work-around is to convert your model interfaces into abstract classes so that they can inherit the attributes appropriately. If this isn't feasible, then you will have to resort to putting the attributes on the concrete classes instead of the interfaces.