Contronoller啟用之後,ASP.NET MVC會根據當前請求上下文得到目標Action的名稱,然後解析出對應的方法並執行之。在整個Action方法的執行過程中,Model中繼資料的解析是一個非常重要的環節。ASP.NET MVC中的Model實際上View Model,表示最終綁定到View上的資料,而Model中繼資料描述了Model的資料結構,以及Model的每個資料成員的一些特性。正是有了Model中繼資料的存在,才使模板化HTML的呈現機製成為可能。此外,Model中繼資料支撐了ASP.NET MVC的Model驗證體系,因為針對Model的驗證規則正是定義在Model中繼資料中。ASP.NET MVC的Model中繼資料通過類型ModelMetadata表示。ModelMetadata通過一系列的屬性描述了Model及其成員相關的中繼資料資訊,在正式介紹這些中繼資料選項之前,我們很有必要先來瞭解一下Model中繼資料層次化結構。
一、Model中繼資料層次化結構
作為Model的資料類型可以一個和簡單的字串或者是一個實值型別的對象,也可能是一個複雜的資料類型。對於一個複雜的資料類型,基於類型本身和資料成員的中繼資料都通過一個ModelMetadata來表示,而某個資料成員又可能是一個複雜類型,所以通過ModelMetadata對象表示的Model中繼資料實際上具有一個樹形層次化結構。
舉個例子,我們具有一個具有如下定義的表示連絡人的資料類型Contact。屬性Name、PhoneNo、EmailAddress和Address分別代表姓名、電話號碼、郵箱地址和聯絡地址。聯絡地址通過另一個資料類型Address表示,屬性Province、City、District和Street分別表示所在省份、城市、城區和街道。
1: public class Contact
2: {
3: public string Name { get; set; }
4: public string PhoneNo { get; set; }
5: public string EmailAddress { get; set; }
6: public Address Address { get; set; }
7: }
8: public class Address
9: {
10: public string Province { get; set; }
11: public string City { get; set; }
12: public string District { get; set; }
13: public string Street { get; set; }
14: }
如果將Contact類型作為Model,作為其中繼資料的ModelMetadata不僅僅具有Contact類型本身和其屬性成員的描述,由於其Address屬性是一個複雜類型,中繼資料還需要描述定義在該類型中的4個屬性成員。下圖反映基於Contact類型的Model中繼資料的層次化結構。
表示Model中繼資料的ModelMetadata類型不僅用於描述某個作為Model的資料類型,還用於遞迴地描述其所有屬性成員(不包含欄位成員),所以ModelMetadata具有一個樹型層次化結構,這也可以從ModelMetadata的定義可以看出來。
1: public class ModelMetadata
2: {
3: //其他成員
4: public virtual IEnumerable<ModelMetadata> Properties { get; }
5: }
如上面的代碼片斷所示,ModelMetadata具有一個類型為IEnumerable<ModelMetadata>的唯讀屬性Properties,表示用於描述屬性/欄位成員的ModelMetadata集合。ModelMetadata的層次化結構可以通過如下圖所示的UML來體現。由於基於類型的ModelMetadata和基於資料成員的ModelMetadata是一種內含項目關聯性,我們可以將前者稱為後者的容器(Container)。