5.Model元数据的提供机制
表示Model元数据的ModelMetadata对象最终是通过一个名为ModelMetadataProvider对象提供的,Model元数据的提供机制是以ModelMetadataProvider为核心的。我们首先来看ModelMetadata的构造函数:
public ModelMetadata(ModelMetadataProvider provider, Type containerType, Func<object> modelAccessor,Type modelType,string propertyName);
定义在ModelMetadata类里面唯一的构造函数如上,如果创建针对属性的Model元数据,可以通过参数propertyName和containerType指定属性名称和容器名称。参数ModelType表示对应数据类型,modelAccessor是一个获取作为Model对象(数据对象)的委托。由于ASP.NET MVC采用了基于数据注解特性的声明式的声明式元数据定义方法,所以它定义了一个名为DataAnnotationsModelMetadata的类来表示采用这种方式定义的Model元数据。如下面代码片段,这个类重写了GetSimpleDisplayText方法,表示简单显示文本的返回值会作为其SimpleDisplayText属性。这个构造函数还提供了一个DisplayColumnAttribute 特性对象作为参数,对于根据这个特性对象创建的
public class DataAnnotationsModelMetadata : ModelMetadata { public DataAnnotationsModelMetadata(DataAnnotationsModelMetadataProvider provider,Type containerType,Func<object> modelAccessor,Type modelType,string propertyName,DisplayColumnAttribute displayColumnAttribute); protected override string GetSimpleDisplayText(); }
DataAnnotationsModelMetadata对象来说,如果特性对象的DisplayColumn属性返回定义在当前数据类中的某个属性名,则对应属性的值将会作为GetSimpleDisplayText的返回值。
6.CachedDataAnnotationsModelMetadata
ASP.NET MVC默认提供的Model元数据其实是一个CachedDataAnnotationsModelMetadata类的对象,这个类也不是上面学的DataAnnotationsModelMetadata类的子类,CachedModelMetadata<TPrototypeCache>是它的基类。 CachedModelMetadata<TPrototypeCache>基类采用了“原型”设计模式,也就是它的一个构造函数里会指定另一个作为原型的CachedModelMetadata<TPrototypeCache>对象,而它自己的一些属性则来自作为原型对象的同名属性。这个基类重写了所有描述Model元数据的属性,并且定义相应的受保护虚方法来得出它们的值且是直接返回基类对应的属性值,CachedDataAnnotationsModelMetadata会重写所有ComputeXxx方法(即相应的受保护虚方法,用来计算出Model元数据的属性)。作为缓存Model元数据信息的类型,CachedDataAnnotationsMetadataAttributes包含了用于定义Model元数据的所有数据注解特性,而CachedDataAnnotationsModelMetadata则是对CachedDataAnnotationsMetadataAttributes的封装,前面提到的ComputeXxx()方法的返回值来源于前面被封装的对象。
7.ModelMetadataProvider
这是一个抽象类,如下所示,GetMetadataForProperties方法用于获取描述指定的容器类型所有属性的Model元数据集合;GetMetadataForPropety方法用于获取描述某个具
public class ModelMetadataProvider { protected ModelMetadataProvider(); public abstract IEnumerable<ModelMetadata> GetMetadataForProperties(object container, Type containerType); public abstract ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, Type containerType, string propertyName); public abstract ModelMetadata GetMetadataForType(Func<object> modelAccessor, Type modelType); }
体属性的Model元数据。而GetMetadataForType方法直接返回针对容器对象和类型的Model元数据。接下来看看3个提供类:
(1)AssociatedMetadataProvider:提供DataAnnotationsModelMetadata的DataAnnotationsModelMetadataProvider及CachedDataAnnotationsModelMetadata的CachedDataAnnotationsModelMetadata都是AssociatedMetadataProvider的子类。这个类根据应用在数据类型或其数据成员上关联的特性来解析Model元数据,根据关联的所有特性列表来创建作为Model元数据的ModelMetadata对象。
(2)DataAnnotationsModelMetadataProvider:这个类在实现的CreateMetadata方法中,它会先从提供的特性列表中提取DisplayColumnAttribute特性并调用构造函数创建一个DataAnnotationsModelMetadata对象,然后利用提供的数据注解特性对其进行初始化。
(3)CachedAssociatedMetadataProvider<TModelMetadata>:这个类中重写的CreateMetadata方法会根据数据类型和属性名称(针对基于属性的Model元数据)生成一个key,并从ObjectCache对象表示的缓存中获取预先创建的ModelMetadata对象。如果缓存的ModelMetadata对象存在,则会调用抽象方法CreateMetadataFormPrototype并创建一个新的ModelMetadata对象,如果没有则会创建作为原型的ModelMetadata对象,该对象在返回之后会被缓存。
总结:ModelMetadataProviders、DataAnnotationsModelMetadataProvider、CachedDataAnnotationsModelMetadataProvider 得到 ModelMetadataProvider;
CachedDataAnnotationsModelMetadataProvider DataAnnotationsModelMetadataProvider可以得到ModelMetadata。