ASP.NET MVC2 ModelMetadataProviders:重写CreateMetadata()和GetMetadataForProperty()之间有什么区别?

CGK*_*CGK 6 asp.net-mvc-2

从MetadataProviders开始,我很想探索框架的扩展点.我目前已经成功实现了填充ModelMetadata.IsRequired属性RequiredAttribute,但我似乎无法找到覆盖之间的区别,CreateMetadata()或者GetMetadataForProperty()因为两个选项似乎都有效.

一般来说,我见过的例子都覆盖了CreateMetadata().

  • 使用这两种选择的利弊是什么?
  • 是否存在其中一个是首选方案的情况?

作为额外的:是否有任何好的资源(博客,书籍)可以从这个扩展点学习?

sma*_*man 8

GetMetadataForProperty()声明的类ModelMetadataProvider.

AssociatedMetadataProvider来源于ModelMetadataProvider. CreateMetadata()被宣布AssociatedMetadataProvider.该DataAnnotationsMetadataProvider是你提供源自链接重写AssociatedMetadataProvider.

MVC框架使得以调用ModelMetadataProviderGetMetadataForProperty()方法.

覆盖的原因CreateMetadata()是因为你AssociatedModelMetadataProvider的默认实现GetMetadataForProperty()调用了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);
Run Code Online (Sandbox Code Playgroud)

}

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);
}
Run Code Online (Sandbox Code Playgroud)

如果您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);
    });
}
Run Code Online (Sandbox Code Playgroud)