在上篇中,給你們留個對Model元數據的印象,並無對Model元數據有過多的講解,而在本篇中也不會對Model元數據的自己來解釋,而是針對於它的生成過程,讓你們可以清楚的瞭解到系統框架是在何時生成Model元數據的,對於Model元數據生成篇幅初定爲兩篇,本篇爲它的總體的生成過程,下篇則爲詳細的生成過程而且會對它自己作一個粗略的介紹,但願你們看完可以有所收穫框架
仍是如前篇說的那樣,既然叫Model元數據(Model指的是視圖模型)那麼確定跟Model有關係了,而在咱們MVC項目中通常是何時會對Model進行操做呢?通常狀況下都是在經過控制器的行爲請求一個視圖的時候,而控制器行爲的參數即爲Model,而後在行爲方法中作一些處理而後再傳遞給視圖。而後再根據上篇最後的一個示意圖來看,ide
圖1spa
生成Model元數據的地方已經鎖定到了行爲方法,想象一下確定是不可能在行爲方法中來生成的,由於那是咱們自定義邏輯的地方。那是在什麼地方呢?code
想必你們看過以前的對過濾器篇幅的介紹,在ASP.NET MVC 過濾器(三)中對行爲過濾器的執行過程講解的時候,中間有提到過模型綁定器,而且說到了系統框架所要使用到的自定義模型綁定器,而使用這個自定義模型綁定器所須要的兩個參數是很是重要的,一個是表示當前控制器上下文的對象ControllerContext,另外一個則是生成Model元數據的關鍵,也是調用自定義模型綁定器的關鍵參數ModelBindingContext類型。看下對象
圖2blog
而在ModelBindingContext類型中有個重要的屬性,即爲Model元數據類型ModelMetadata,由此能夠知道在咱們的控制器行爲執行以前,對應控制器行爲的Model的Model元數據ModelMetadata類型已經生成了。(這部份內容詳見過濾器篇幅)繼承
而它是怎麼生成的呢?是經過系統框架中默認提供的提供程序來生成的,是哪些個類型呢?遞歸
圖3接口
那咱們就先看一下最頂層的基類ModelMetadataProvider的定義:ip
代碼1-1
public abstract class ModelMetadataProvider { // 摘要: // 在派生類中重寫時,初始化派生自 System.Web.Mvc.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); }
很是明白的定義,三個抽象方法,這裏咱們只需先看GetMetadataForType()方法,其它兩個暫時無論下篇中會有講到,由於先看GetMetadataForType()方法呢?由於它是生成ModelMetadata類型的入口,第一個參數暫時忽略,第二個參數嘛很重要了,是ParameterDescriptor類型的ParameterType屬性,表示着Model的類型(也就是控制器方法參數的Type類型),如今咱們來看下圖4
圖4
圖4中藍色線條爲主要流程,紅色線條是在藍色處理以後執行的流程。
上面說到,入口方法是爲抽象方法,那是怎麼具體實現的呢,從圖4中能夠看到是由實現了ModelMetadataProvider的類型AssociatedMetadataProvider類型來進行處理的,從圖4能夠看到首先是獲取一個AttributeList的類型,AttributeList類型表示着從AssociatedMetadataProvider類型GetMetadataForType()方法參數modelType類型上的特性集合,對了AssociatedMetadataProvider類型是比較重要的類型,咱們先來看一下它的定義:
public abstract class AssociatedMetadataProvider : ModelMetadataProvider { protected AssociatedMetadataProvider(); protected abstract ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName); protected virtual IEnumerable<Attribute> FilterAttributes(Type containerType, PropertyDescriptor propertyDescriptor, IEnumerable<Attribute> attributes); public override IEnumerable<ModelMetadata> GetMetadataForProperties(object container, Type containerType); protected virtual ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, Type containerType, PropertyDescriptor propertyDescriptor); public override ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, Type containerType, string propertyName); public override ModelMetadata GetMetadataForType(Func<object> modelAccessor, Type modelType); protected virtual ICustomTypeDescriptor GetTypeDescriptor(Type type); }
方法有點多,暫時不用管,大多數方法都是用來在遞歸生成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元數據系列的文章後應該會有所瞭解,將在後續的篇章中慢慢的揭開它的祕密。謝謝你們的支持。
做者:金源
出處:http://www.cnblogs.com/jin-yuan/
本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面