ASP.NET MVC2 ModelMetadataProviders: какая разница между переопределением CreateMetadata () и GetMetadataForProperty () - PullRequest
6 голосов
/ 09 февраля 2011

Я собираюсь исследовать точки расширения фреймворка, начиная с MetadataProviders.В настоящее время я реализовал заполнение свойства ModelMetadata.IsRequired с помощью RequiredAttribute успешно, но я не могу найти разницу между переопределением CreateMetadata() или GetMetadataForProperty(), так как оба варианта работают.

В общем, примеры, которые я видел, переопределяют CreateMetadata().

  • Каковы преимущества и недостатки использования любого из параметров?
  • Существуют ли сценарии, в которыходин из них является предпочтительным вариантом?

В качестве дополнения: есть ли какие-нибудь полезные ресурсы (блоги, книги) для изучения из этой точки расширения?

1 Ответ

8 голосов
/ 14 февраля 2011

GetMetadataForProperty() объявлено для класса ModelMetadataProvider.

AssociatedMetadataProvider происходит от ModelMetadataProvider. CreateMetadata() объявлено AssociatedMetadataProvider. Значение DataAnnotationsMetadataProvider, которое переопределено в указанной вами ссылке, получено из AssociatedMetadataProvider.

Инфраструктура MVC выполняет вызовы ModelMetadataProvider GetMetadataForProperty() метода.

Причина, по которой переопределение CreateMetadata() работает для вас, заключается в том, что реализация GetMetadataForProperty() по умолчанию *1019* делает вызов CreateMetadata(). Это выглядит так:

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(MvcResources.Common_NullOrEmpty, "propertyName");
   }
   PropertyDescriptor propertyDescriptor = this.GetTypeDescriptor(containerType).GetProperties().Find(propertyName, true);
   if (propertyDescriptor == null)
   {
       throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, MvcResources.Common_PropertyNotFound, new object[] { containerType.FullName, propertyName   }));
   }
return this.GetMetadataForProperty(modelAccessor, containerType, propertyDescriptor);

}

protected virtual ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, Type containerType, PropertyDescriptor propertyDescriptor) 
{
   IEnumerable<Attribute> attributes = this.FilterAttributes(containerType, propertyDescriptor, propertyDescriptor.Attributes.Cast<Attribute>());
   return this.CreateMetadata(attributes, containerType, modelAccessor, propertyDescriptor.PropertyType, propertyDescriptor.Name);
}

Если вы подклассифицируете AssociatedMetadataProvider по той ссылке, которую вы указали, то предпочитаемым пунктом расширения является метод CreateMetadata, поскольку метод AssociatedMetadataProvider.GetMetadataForProperty() предварительно проверяет контракт вашего метода CreateMetadata(). Таким образом, вы знаете, что если в вашем методе CreateMetadata() есть ошибка, вы уже знаете, что источник ошибки находится в вашем методе, а не в аргументах, которые ему были переданы.

Также, вот источник FilterAttributes() метода, если вам интересно:

protected virtual IEnumerable<Attribute> FilterAttributes(Type containerType, PropertyDescriptor propertyDescriptor, IEnumerable<Attribute> attributes)
{
if (!typeof(ViewPage).IsAssignableFrom(containerType) && !typeof(ViewUserControl).IsAssignableFrom(containerType))
    {
        return attributes;
    }
    return attributes.Where<Attribute>(delegate (Attribute a) {
        return !(a is ReadOnlyAttribute);
    });
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...