天天看点

ASP.NET MVC Model元数据(二)ASP.NET MVC Model元数据(二)

在上篇中,给大家留个对Model元数据的印象,并没有对Model元数据有过多的讲解,而在本篇中也不会对Model元数据的本身来解释,而是针对于它的生成过程,让大家能够清楚的了解到系统框架是在什么时候生成Model元数据的,对于Model元数据生成篇幅初定为两篇,本篇为它的整体的生成过程,下篇则为详细的生成过程并且会对它本身做一个粗略的介绍,希望大家看完能够有所收获

什么是Model元数据?

生成Model元数据的过程【一】

生成Model元数据的过程【二】

ModelMetaData的定义、详解

Model元数据应用(常用特性应用)-1

Model元数据应用(自定义视图模板)-2

Model元数据应用(IMetadataAware接口使用)-3

还是如前篇说的那样,既然叫Model元数据(Model指的是视图模型)那么肯定跟Model有关系了,而在我们MVC项目中一般是什么时候会对Model进行操作呢?一般情况下都是在通过控制器的行为请求一个视图的时候,而控制器行为的参数即为Model,然后在行为方法中做一些处理然后再传递给视图。然后再根据上篇最后的一个示意图来看,

图1

ASP.NET MVC Model元数据(二)ASP.NET MVC Model元数据(二)

生成Model元数据的地方已经锁定到了行为方法,想象一下肯定是不可能在行为方法中来生成的,因为那是我们自定义逻辑的地方。那是在什么地方呢?

想必大家看过之前的对过滤器篇幅的介绍,在ASP.NET MVC 过滤器(三)中对行为过滤器的执行过程讲解的时候,中间有提到过模型绑定器,并且说到了系统框架所要使用到的自定义模型绑定器,而使用这个自定义模型绑定器所需要的两个参数是非常重要的,一个是表示当前控制器上下文的对象ControllerContext,另一个则是生成Model元数据的关键,也是调用自定义模型绑定器的关键参数ModelBindingContext类型。看下

图2

ASP.NET MVC Model元数据(二)ASP.NET MVC Model元数据(二)

而在ModelBindingContext类型中有个重要的属性,即为Model元数据类型ModelMetadata,由此可以知道在我们的控制器行为执行之前,对应控制器行为的Model的Model元数据ModelMetadata类型已经生成了。(这部分内容详见过滤器篇幅)

而它是怎么生成的呢?是通过系统框架中默认提供的提供程序来生成的,是哪些个类型呢?

图3

ASP.NET MVC Model元数据(二)ASP.NET MVC Model元数据(二)

那我们就先看一下最顶层的基类ModelMetadataProvider的定义:

代码1-1

1

2

3

4

5

6

7

8

9

<code>public</code> <code>abstract</code> <code>class</code> <code>ModelMetadataProvider</code>

<code>    </code><code>{</code>

<code>        </code><code>// 摘要:</code>

<code>        </code><code>//     在派生类中重写时,初始化派生自 System.Web.Mvc.ModelMetadataProvider 类的对象的新实例。</code>

<code>        </code><code>protected</code> <code>ModelMetadataProvider();</code>

<code>        </code><code>public</code> <code>abstract</code> <code>IEnumerable&lt;ModelMetadata&gt; GetMetadataForProperties(</code><code>object</code> <code>container, Type containerType);</code>

<code>        </code><code>public</code> <code>abstract</code> <code>ModelMetadata GetMetadataForProperty(Func&lt;</code><code>object</code><code>&gt; modelAccessor, Type containerType, </code><code>string</code> <code>propertyName);</code>

<code>        </code><code>public</code> <code>abstract</code> <code>ModelMetadata GetMetadataForType(Func&lt;</code><code>object</code><code>&gt; modelAccessor, Type modelType);</code>

<code>    </code><code>}</code>

非常明白的定义,三个抽象方法,这里我们只需先看GetMetadataForType()方法,其它两个暂时不管下篇中会有讲到,因为先看GetMetadataForType()方法呢?因为它是生成ModelMetadata类型的入口,第一个参数暂时忽略,第二个参数嘛很重要了,是ParameterDescriptor类型的ParameterType属性,表示着Model的类型(也就是控制器方法参数的Type类型),现在我们来看下图4

图4

ASP.NET MVC Model元数据(二)ASP.NET MVC Model元数据(二)

图4中蓝色线条为主要流程,红色线条是在蓝色处理之后执行的流程。

上面说到,入口方法是为抽象方法,那是怎么具体实现的呢,从图4中可以看到是由实现了ModelMetadataProvider的类型AssociatedMetadataProvider类型来进行处理的,从图4可以看到首先是获取一个AttributeList的类型,AttributeList类型表示着从AssociatedMetadataProvider类型GetMetadataForType()方法参数modelType类型上的特性集合,对了AssociatedMetadataProvider类型是比较重要的类型,我们先来看一下它的定义:

10

11

<code>public</code> <code>abstract</code> <code>class</code> <code>AssociatedMetadataProvider : ModelMetadataProvider</code>

<code>        </code><code>protected</code> <code>AssociatedMetadataProvider();</code>

<code>        </code><code>protected</code> <code>abstract</code> <code>ModelMetadata CreateMetadata(IEnumerable&lt;Attribute&gt; attributes, Type containerType, Func&lt;</code><code>object</code><code>&gt; modelAccessor, Type modelType, </code><code>string</code> <code>propertyName);</code>

<code>        </code><code>protected</code> <code>virtual</code> <code>IEnumerable&lt;Attribute&gt; FilterAttributes(Type containerType, PropertyDescriptor propertyDescriptor, IEnumerable&lt;Attribute&gt; attributes);</code>

<code>        </code><code>public</code> <code>override</code> <code>IEnumerable&lt;ModelMetadata&gt; GetMetadataForProperties(</code><code>object</code> <code>container, Type containerType);</code>

<code>        </code><code>protected</code> <code>virtual</code> <code>ModelMetadata GetMetadataForProperty(Func&lt;</code><code>object</code><code>&gt; modelAccessor, Type containerType, PropertyDescriptor propertyDescriptor);</code>

<code>        </code><code>public</code> <code>override</code> <code>ModelMetadata GetMetadataForProperty(Func&lt;</code><code>object</code><code>&gt; modelAccessor, Type containerType, </code><code>string</code> <code>propertyName);</code>

<code>        </code><code>public</code> <code>override</code> <code>ModelMetadata GetMetadataForType(Func&lt;</code><code>object</code><code>&gt; modelAccessor, Type modelType);</code>

<code>        </code><code>protected</code> <code>virtual</code> <code>ICustomTypeDescriptor GetTypeDescriptor(Type type);</code>

方法有点多,暂时不用管,大多数方法都是用来在递归生成Model元数据的时候使用的(具体的过程会在下篇中讲解)。好了切回主题接着上面的内容来说,AttributeList类型的由来,是通过ModelMetadataProvider的GetTypeDescriptor()方法根据Model的类型(这里暂且先这么理解,等看完下个篇幅就会知道这里也有可能是Model中的属性类型)来生成一个ICustomTypeDescriptor类型(可以想象成这是对于一种对象类型元数据描述对象的抽象定义。读起来有点绕口,但是确实是这么个意思)。而系统会有个默认的自定义实现来实现这个接口类型,我们通过这个默认的实现来获得Model类型的AttributeList类型。

在有了AttributeList类型后,我们就可以调用AssociatedMetadataProvider类型的CreateMetadata()方法来创建Model元数据对象,但是这个CreateMetadata()的定义是抽象的,而真正的实现是由继承了AssociatedMetadataProvider类型的DataAnnotationsModelMetadataProvider类型,由此过后我们生成得到ModelMetadata元数据对象(真正的过程比较繁琐,不然也不会另起一篇专门用来讲解生成的过程),得到了Model元数据对象过后并没有结束,而是继续调用了AssociatedMetadataProvider类型的ApplyMetadataAwareAttributes()方法,并在此方法中,系统框架会调用我们自定义实现了IMetadataAware接口类型的对象,来对Model元数据对象进行个性化修改,并且最后才会真正的返回Model元数据对象。

有可能看到这里有的朋友对Model元数据还是不怎么清楚和了解,朋友们急我也急,如果我分享的这些知识大家看完都不知所云那我又是何必呢。先不要急看了多少就是多少在看完这个Model元数据系列的文章后应该会有所了解,将在后续的篇章中慢慢的揭开它的秘密。谢谢大家的支持。

     本文转自jinyuan0829 51CTO博客,原文链接:http://blog.51cto.com/jinyuan/1429642,如需转载请自行联系原作者

继续阅读