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元数据层次化结构。[《How ASP.NET MVC Works?》中]

目录 
一、Model元数据层次化结构 
二、基本Model元数据信息 
三、Model元数据的定制 
    UIHintAttribute 
    HiddenInputAttribute与ScaffoldColumnAttribute 
    DataTypeAttribute与DisplayFormatAttribute 
    EditableAttribute与ReadOnlyAttribute 
    DisplayAttribute与DisplayNameAttribute 
    RequiredAttribute 
四、IMetadataAware接口 
    AllowHtmlAttribute 
    实例演示:创建实现IMetadataAware接口的特性定制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元数据的层次化结构。

MVC之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)。

MVC之Model元数据

二、基本Model元数据信息

基于作为Model类型创建的元数据主要是为View实现模板化HTML呈现和数据验证服务的,我们可以通过在类型和数据成员上应用相应的特性控制Model在View中的呈现方式或者定义相应的验证规则。在介绍声明式Model元数据编程方式之前,我们先来介绍表示Model元数据的ModelMetadata类型中与UI呈现和数据验证无关的基本属性。

  1     // Summary:
  2     //     No content here will be updated; please do not add material here.
  3     public class ModelMetadata
  4     {
  5         // Summary:
  6         //     Initializes a new instance of the System.Web.Http.Metadata.ModelMetadata
  7         //     class.
  8         //
  9         // Parameters:
 10         //   provider:
 11         //     The provider.
 12         //
 13         //   containerType:
 14         //     The type of the container.
 15         //
 16         //   modelAccessor:
 17         //     The model accessor.
 18         //
 19         //   modelType:
 20         //     The type of the model.
 21         //
 22         //   propertyName:
 23         //     The name of the property.
 24         public ModelMetadata(ModelMetadataProvider provider, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName);
 25 
 26         // Summary:
 27         //     Gets a dictionary that contains additional metadata about the model.
 28         //
 29         // Returns:
 30         //     A dictionary that contains additional metadata about the model.
 31         public virtual Dictionary<string, object> AdditionalValues { get; }
 32         //
 33         // Summary:
 34         //     Gets or sets the type of the container for the model.
 35         //
 36         // Returns:
 37         //     The type of the container for the model.
 38         public Type ContainerType { get; }
 39         //
 40         // Summary:
 41         //     Gets or sets a value that indicates whether empty strings that are posted
 42         //     back in forms should be converted to null.
 43         //
 44         // Returns:
 45         //     true if empty strings that are posted back in forms should be converted to
 46         //     null; otherwise, false. The default value is true.
 47         public virtual bool ConvertEmptyStringToNull { get; set; }
 48         //
 49         // Summary:
 50         //     Gets or sets the description of the model.
 51         //
 52         // Returns:
 53         //     The description of the model. The default value is null.
 54         public virtual string Description { get; set; }
 55         //
 56         // Summary:
 57         //     Gets or sets a value that indicates whether the model is a complex type.
 58         //
 59         // Returns:
 60         //     A value that indicates whether the model is considered a complex.
 61         public virtual bool IsComplexType { get; }
 62         //
 63         // Summary:
 64         //     Gets a value that indicates whether the type is nullable.
 65         //
 66         // Returns:
 67         //     true if the type is nullable; otherwise, false.
 68         public bool IsNullableValueType { get; }
 69         //
 70         // Summary:
 71         //     Gets or sets a value that indicates whether the model is read-only.
 72         //
 73         // Returns:
 74         //     true if the model is read-only; otherwise, false.
 75         public virtual bool IsReadOnly { get; set; }
 76         //
 77         // Summary:
 78         //     Gets the value of the model.
 79         //
 80         // Returns:
 81         //     The model value can be null.
 82         public object Model { get; set; }
 83         //
 84         // Summary:
 85         //     Gets the type of the model.
 86         //
 87         // Returns:
 88         //     The type of the model.
 89         public Type ModelType { get; }
 90         //
 91         // Summary:
 92         //     Gets a collection of model metadata objects that describe the properties
 93         //     of the model.
 94         //
 95         // Returns:
 96         //     A collection of model metadata objects that describe the properties of the
 97         //     model.
 98         public virtual IEnumerable<ModelMetadata> Properties { get; }
 99         //
100         // Summary:
101         //     Gets the property name.
102         //
103         // Returns:
104         //     The property name.
105         public string PropertyName { get; }
106         //
107         // Summary:
108         //     Gets or sets the provider.
109         //
110         // Returns:
111         //     The provider.
112         protected ModelMetadataProvider Provider { get; set; }
113 
114         // Summary:
115         //     Gets the display name for the model.
116         //
117         // Returns:
118         //     The display name for the model.
119         public string GetDisplayName();
120         //
121         // Summary:
122         //     Gets a list of validators for the model.
123         //
124         // Parameters:
125         //   validatorProviders:
126         //     The validator providers for the model.
127         //
128         // Returns:
129         //     A list of validators for the model.
130         public virtual IEnumerable<Web.Http.Validation.ModelValidator> GetValidators(IEnumerable<Web.Http.Validation.ModelValidatorProvider> validatorProviders);
ModelMetadata

1: public class ModelMetadata
   2: {
   3:    //其他成员
   4:     public Type ModelType { get; }
   5:     public virtual bool IsComplexType { get; }
   6:     public bool IsNullableValueType { get; }
   7:     public Type ContainerType { get; }
   8:  
   9:     public object Model { get; set; }
  10:     public string PropertyName { get; }
  11:  
  12:     public virtual Dictionary<string, object> AdditionalValues { get; }
  13:     protected ModelMetadataProvider Provider { get; set; }
  14: }


相关文章: