ASP.NET MVC的Model元数据提供机制的实现2012-11-24 cnblogs 蒋金楠在前面的介绍中我们已经提到过表示Model元数据的ModelMetadata对象最终是通过一个名为ModelMetadataProvider的组件提供的,接下来我们着重讨论基于ModelMetadataProvider的Model元数据提供机制及其扩展。一、 ModelMetadataProvider在ASP.NET MVC的Model元数据相关的应用编程接口中,用于创建Model元数据的ModelMetadataProvider接继承自抽象类ModelMetadataProvider。如下面的代码片断所示,ModelMetadataProvide具有三个抽象方法。GetMetadataForProperties方法用于获取表示针对指定容器对象和类型所有属性的Model元数据集合,GetMetadataForProperty获取针对指定容器对象和类型某个具体属性对象的Model元数据,而GetMetadataForType则直接返回针对容器对象和类型的Model元数据。
 1: public abstract class ModelMetadataProvider
 2: {
 3: public abstract IEnumerable<ModelMetadata> GetMetadataForProperties( object container, Type containerType);
 4: public abstract ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, Type containerType, string propertyName);
 5: public abstract ModelMetadata GetMetadataForType(Func<object> modelAccessor, Type modelType);
 6: }
注:在本文中提及的ModelMetadataProvider在大部分情况泛指直接或者间接继承自抽象类ModelMetadataProvider,用于提供Model元数据的提供者对象或者类型,请读者注意区分。在ASP.NET MVC的元数据解析系统中使用的ModelMetadataProvider最终通过类型ModelMetadataProviders获取。如下面的代码片断所示,ModelMetadataProviders具有一个ModelMetadataProvider类型的静态可读可写属性Current用于获取和设置当前使用的ModelMetadataProvider。
 1: public class ModelMetadataProviders
 2: {
 3: public static ModelMetadataProvider Current { get; set; }
 4: }
二、DataAnnotationsModelMetadataProvider通过前面的介绍我们知道Model元数据是通过定义在System.ComponentModel.DataAnnotations命名空间下的标注特性来定义的,Model元数据解析系统通过对应用在表示Model的数据类型及其属性成员的标注特性进行解析从而对创建的Model元数据进行对应的初始化,而这个工作是通过DataAnnotationsModelMetadataProvider来实现的。不过DataAnnotationsModelMetadataProvider并没有直接继承自ModelMetadataProvider,而是继承自抽象类AssociatedMetadataProvider,后者是ModelMetadataProvider的子类。AssociatedMetadataProvider的主要作用是对应用在Model类型或属性上所有“关联”的特性,这也是它命名的由来。如下面的代码片断所示,AssociatedMetadataProvider实现了定义在ModelMetadataProvider的三个方法。
 1: public abstract class AssociatedMetadataProvider : ModelMetadataProvider
 2: {
 3: protected abstract ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName);
 4:
 5: public override IEnumerable<ModelMetadata> GetMetadataForProperties(object container, Type containerType);
 6: public override ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, Type containerType, string propertyName);
 7: public override ModelMetadata GetMetadataForType(Func<object> modelAccessor, Type modelType);
 8: }
对于AssociatedMetadataProvider实现的三个方法,它并紧紧是通过反射将应用在Model类型和对应属性上的所有特性,并将这个特性列表作为参数(attributes)传入抽象方法CreateMetadata完成Model元数据的创建。值得一提的是,当通过调用CreateMetadata创建出ModelMetadata之后,会从特性列表中筛选出实现了IMetadataAware接口的特性,并将该ModelMetadata对象作为参数调用它们的OnMetadataCreated方法。继承自AssociatedMetadataProvider的DataAnnotationsModelMetadataProvider实现了抽象方法,它根据传入的特性列表以及其他相关的信息(用于创建Model对象的委托、容器和Model类型以及属性名称)实现对Model元数据的最终创建。下面的代码片断就是整个DataAnnotationsModelMetadataProvider类型的定义。
 1: public class DataAnnotationsModelMetadataProvider : AssociatedMetadataProvider
 2: {
 3: public DataAnnotationsModelMetadataProvider();
 4: protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType,
 5: Func<object> modelAccessor, Type modelType, string propertyName);
 6: }
包含在Model元数据提供系统的ModelMetadataProvider、AssociatedMetadataProvider、DataAnnotationsModelMetadataProvider和ModelMetadataProviders与ModelMetadata之间的关系可以通过如下图所示的UML来体现。

DataAnnotationsModelMetadataProvider最终实现了基于标注特性的Model元数据的解析,但是在默认情况下使用的ModelMetadataProvider类型却不是DataAnnotationsModelMetadataProvider,而是CachedDataAnnotationsModelMetadataProvider,它对解析出来的元数据信息进行了相应的环村以提供性能,其实最终实现对Model元数据创建的还是DataAnnotationsModelMetadataProvider。