Продолжая Ответ Энтони Джонстона , вы можете обнаружить, что вы получаете исключения при использовании DataAnnotations, так как метод AssociatedValidatorProvider.GetValidatorsForProperty () попытается использовать интерфейс наследования в качестве типа контейнера а не базовый и, следовательно, не удается найти свойство снова.
Это отраженный код из метода GetValidatorsForProperty (это вторая строка, которая приводит к тому, что переменная propertyDescriptor имеет значение null и, следовательно, генерируется исключение):
private IEnumerable<ModelValidator> GetValidatorsForProperty(ModelMetadata metadata, ControllerContext context)
{
ICustomTypeDescriptor typeDescriptor = this.GetTypeDescriptor(metadata.ContainerType);
PropertyDescriptor propertyDescriptor = typeDescriptor.GetProperties().Find(metadata.PropertyName, true);
if (propertyDescriptor != null)
{
return this.GetValidators(metadata, context, propertyDescriptor.Attributes.OfType<Attribute>());
}
else
{
object[] fullName = new object[] { metadata.ContainerType.FullName, metadata.PropertyName };
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, MvcResources.Common_PropertyNotFound, fullName), "metadata");
}
}
Если это так, я полагаю, что следующий код может помочь, поскольку он гарантирует, что для ContainerType задан тип, на котором установлено свойство, а не тип модели представления.
Отказ от ответственности: Кажется, он работает нормально, но я еще не проверил его полностью, поэтому он может иметь нежелательные эффекты! Я также понимаю, что это написано не совсем идеально, но я пытался сохранить формат, аналогичный предыдущему ответу для удобства сравнения. :)
public class MyMetadataProvider : DataAnnotationsModelMetadataProvider
{
public override ModelMetadata GetMetadataForProperty(
Func<object> modelAccessor, Type containerType, string propertyName)
{
if (containerType == null)
{
throw new ArgumentNullException("containerType");
}
if (String.IsNullOrEmpty(propertyName))
{
throw new ArgumentException(
"The property '{0}' cannot be null or empty", "propertyName");
}
var containerTypeToUse = containerType;
var property = GetTypeDescriptor(containerType)
.GetProperties().Find(propertyName, true);
if (property == null
&& containerType.IsInterface)
{
var foundProperty = (from t in containerType.GetInterfaces()
let p = GetTypeDescriptor(t).GetProperties()
.Find(propertyName, true)
where p != null
select (new Tuple<System.ComponentModel.PropertyDescriptor, Type>(p, t))
).FirstOrDefault();
if (foundProperty != null)
{
property = foundProperty.Item1;
containerTypeToUse = foundProperty.Item2;
}
}
if (property == null)
{
throw new ArgumentException(
String.Format(
CultureInfo.CurrentCulture,
"The property {0}.{1} could not be found",
containerType.FullName, propertyName));
}
return GetMetadataForProperty(modelAccessor, containerTypeToUse, property);
}
}