標籤:asp.net mvc metadata asp.net mvc .net c# mvc
ASP.NET MVC Model中繼資料(三)
前言
在上篇中我們大概的講解了Model中繼資料的產生過程,並沒有對Model中繼資料本身和詳細的產生過程有所描述,本篇將會對詳細的產生過程進行講解,並且會對Model中繼資料本身的結構稍作講解,讀完本篇過後你將會對Model中繼資料的結構有個很清晰的印象。
Model中繼資料
- 什麼是Model中繼資料?
- 產生Model中繼資料的過程【一】
- 產生Model中繼資料的過程【二】
- ModelMetaData的定義、詳解
- Model中繼資料應用(常用特性應用)-1
- Model中繼資料應用(自訂視圖模板)-2
- Model中繼資料應用(IMetadataAware介面使用)-3
產生Model中繼資料的過程【二】
還記得Model中繼資料系列篇的第一章裡的最後一幅圖嗎?
圖1
沒有錯,MVC架構根據我們定義的視圖模型產生了一個Model中繼資料ModelMetadata(實際為DataAnnotationsModelMetadata類型是繼承自ModelMetadata類型的,在下文中為了更直觀的方便講解所以還是用ModelMetadata類型來作介紹)。我們來看一下ModelMetadata類型的定義:
代碼1-1
public class ModelMetadata { public ModelMetadata(ModelMetadataProvider provider, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName); // // 摘要: // 擷取模型中繼資料對象的集合,這些對象描述模型的屬性。 // // 返回結果: // 用於描述模型屬性的模型中繼資料對象的集合。 public virtual IEnumerable<ModelMetadata> Properties { get; }// // 摘要: // 擷取模型的類型。 // // 返回結果: // 模型的類型。 public Type ModelType { get; } protected ModelMetadataProvider Provider { get; set; } …… }
只留了個建構函式和三個屬性,詳細的部分下篇會講到,建構函式中的第一個參數類型大家肯定很熟悉,那就是上篇中講到的Model中繼資料產生程式,用來產生Model中繼資料(ModelMetadata類型)的,這樣的是把ModelMetadataProvider類型的引用設定到Model中繼資料的內部,也就是Provider屬性,這樣做是有目的的隨後就會講到,在其定義中還有個Properties屬性,類型大家都看到了是ModelMetadata類型的集合,這就是ModelMetadata類型關鍵的所在了,Properties屬性工作表示著當前ModelMetadata的所描述類型中的屬性中繼資料集合。
圖2
用前篇介紹過的Customer類型來做描述,對應著Customer類型的結構MVC架構也會產生對應的ModelMetadata類型結構,這裡捎帶提一下,對於Address屬性類型是Address類型這種屬於複雜類型,MVC架構會向下繼續產生就如同產生Customer類型一樣。
那麼這樣的結構是怎麼產生的呢?當然不用說了,是依靠Provider屬性也就是ModelMetadataProvider類型的引用來產生結構的,3所示:
圖3
首先根據當前Model中繼資料ModelMetadata類型(對應的對象是Customer類型)中的Model屬性和ModelType屬性來作為參數調用AssociatedMetadataProvider類型的GetMetadataForProperties()方法,這裡說一下ModelMetadata類型的Model屬性,表示著當前Model中繼資料所對應對象的值,也是用這個值來判斷是否是複雜類型的,ModelType屬性上面說過。
在GetMetadataForProperties()方法中會先根據自訂類型描述類型的GetProperties()方法來擷取當前對象是Customer類型的所有的屬性,並且封裝成屬性描述類型集合。
隨後根據擷取到的屬性描述類型集合,遍曆此集合并且根據遍曆中的單個屬性描述類型調用AssociatedMetadataProvider類型中的GetMetadataForProperty()方法,這裡要說的是第一個參數modelAccessor預設是Null的,第二個參數containerType是表示著當前Customer類型,第三個參數就是屬性描述類型了裡麵包含著屬性類型的所有資訊。有的朋友會問說明這些屬性做什麼,因為等下會說到第二個參數containerType的。
在AssociatedMetadataProvider類型中的GetMetadataForProperty()方法中,會根據PropertyDescriptor類型的參數擷取到當前屬性上所有描述資訊(也就是那些屬性類別),比如當前的PropertyDescriptor類型是結構化Customer類型中的CustomerID,那圖3中AttrbuteList類型中就是包含著所有依附在這個屬性上的屬性類別。後續的產生過程還是跟上篇的講解的一樣依舊的調用了AssociatedMetadataProvider類型的CreateMetadata(),只不過在AssociatedMetadataProvider類型中方法是抽象中,實際是由它的實作類別DataAnnotationsModelMetadataProvider中的CreateMetadata()方法來完成的。
這裡大家可能會發現,在圖3中黃色框中的操作都是屬於遍曆中的操作,就是每次都會只會產生一個ModelMetadata類型執行個體然後最後合并在一起返回出去。
還有要說的就是在圖3中黃色框中的每個調用的函數都有個Type類型的containerType參數,這就是上面說過的Customer類型,並且在產生的ModelMetadata類型執行個體中賦值到ContainerType屬性,表示著新產生的ModelMetadata類型執行個體比如叫A,A中描述的資訊就是Customer類型中的CustomerID屬性的所有資訊,而A中的ContainerType屬性就是表示描述的CustomerID屬性是屬於哪個類型的。
這裡還有要說的,就是在系統預設產生的時候,比如說視圖模型是Customer類型,那麼MVC架構只會產生一個ModelMetadata類型的執行個體假使它叫M,因為M自身並沒有自己檢測自己是不是複雜類型,所以M是不會調用提供器往下產生的,而是在外部要使用M了才會去調用M中的函數檢測M是不是複雜類型然後往下產生,假使現在MVC架構中使用到了這個M可能就會調用檢測它自身的方法來檢查它是不是複雜類型,明顯的Customer類型是複雜類型,這個時候M會按照本篇描述的那樣依次的產生它所描述類型中的屬性,也只是僅限於這一層,有的朋友可能會問在Customer類型中Address屬性也是複雜類型,對的,但是M只會去產生Address屬性本身的ModelMetadata類型的執行個體,而不會去產生Address屬性的內部。
現在大家再看一次圖2,是不是有點清晰的感覺。
(有哪位大神知道在MVC架構中是在哪裡調用ModelMetadata類型執行個體的自身檢測的?知道的告知一下小弟以身相許,找的頭破血流也沒找到,我相信是肯定有的)
本篇結束,下篇中詳細介紹DataAnnotationsModelMetadataProvider類型中的CreateMetadata()方法,從這個方法進入,詳細的講解ModelMetadata物件類型。
金源
出處:http://blog.csdn.net/jinyuan0829
本文著作權歸作者和CSDN共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面