一. 元数据描述类型ModelMetadata
模型元数据是对Model的描述信息,在ASP.NET MVC框架中有非常重要的作用,在模型绑定,模型验证,模型呈现等许多地方都有它的身影。描述Model元数据的基本类型是ModelMetadata,日常开发中我们建立的ViewModel,在上面的声明的许多属性最终都会反应的该类型上,它的具体定义如下:
1 public class ModelMetadata 2 { 3 // 摘要: 4 // 默认顺序值 10000。 5 public const int DefaultOrder = 10000; 6 7 // 摘要: 8 // 初始化 System.Web.Mvc.ModelMetadata 类的新实例。 9 // 10 // 参数: 11 // provider: 12 // 提供程序。 13 // 14 // containerType: 15 // 容器的类型。 16 // 17 // modelAccessor: 18 // 模型访问器。 19 // 20 // modelType: 21 // 模型的类型。 22 // 23 // propertyName: 24 // 模型的名称。 25 public ModelMetadata(ModelMetadataProvider provider, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName); 26 27 // 摘要: 28 // 获取包含有关模型的其他元数据的字典。 29 // 30 // 返回结果: 31 // 包含有关模型的其他元数据的字典。 32 public virtual Dictionary<string, object> AdditionalValues { get; } 33 // 34 // 摘要: 35 // 获取或设置模型的容器的类型。 36 // 37 // 返回结果: 38 // 模型的容器的类型。 39 public Type ContainerType { get; } 40 // 41 // 摘要: 42 // 获取或设置一个值,该值指示在窗体中回发的空字符串是否应转换为 null。 43 // 44 // 返回结果: 45 // 如果在窗体中回发的空字符串应转换为 null,则为 true;否则为 false。默认值为 true。 46 public virtual bool ConvertEmptyStringToNull { get; set; } 47 // 48 // 摘要: 49 // 获取或设置有关数据类型的元信息。 50 // 51 // 返回结果: 52 // 有关数据类型的元信息。 53 public virtual string DataTypeName { get; set; } 54 // 55 // 摘要: 56 // 获取或设置模型的说明。 57 // 58 // 返回结果: 59 // 模型的说明。默认值为 null。 60 public virtual string Description { get; set; } 61 // 62 // 摘要: 63 // 获取或设置模型的显示格式字符串。 64 // 65 // 返回结果: 66 // 模型的显示格式字符串。 67 public virtual string DisplayFormatString { get; set; } 68 // 69 // 摘要: 70 // 获取或设置模型的显示名称。 71 // 72 // 返回结果: 73 // 模型的显示名称。 74 public virtual string DisplayName { get; set; } 75 // 76 // 摘要: 77 // 获取或设置模型的编辑格式字符串。 78 // 79 // 返回结果: 80 // 模型的编辑格式字符串。 81 public virtual string EditFormatString { get; set; } 82 // 83 // 摘要: 84 // 获取或设置一个值,该值指示是否应该使用关联的 HTML 元素呈现模型对象。 85 // 86 // 返回结果: 87 // 如果包含模型对象的关联 HTML 元素应包含在该对象中,则为 true;否则为 false。 88 public virtual bool HideSurroundingHtml { get; set; } 89 // 90 // 摘要: 91 // 获取或设置一个值,该值指示模型是否为复杂类型。 92 // 93 // 返回结果: 94 // 一个值,指示 MVC 框架是否将模型视为复杂类型。 95 public virtual bool IsComplexType { get; } 96 // 97 // 摘要: 98 // 获取一个值,该值指示类型是否可为 null。 99 // 100 // 返回结果: 101 // 如果该类型可为 null,则为 true;否则为 false。 102 public bool IsNullableValueType { get; } 103 // 104 // 摘要: 105 // 获取或设置一个值,该值指示模型是否为只读。 106 // 107 // 返回结果: 108 // 如果该模型为只读,则为 true;否则为 false。 109 public virtual bool IsReadOnly { get; set; } 110 // 111 // 摘要: 112 // 获取或设置一个值,该值指示模型是否为必需的。 113 // 114 // 返回结果: 115 // 如果该模型是必需的,则为 true;否则为 false。 116 public virtual bool IsRequired { get; set; } 117 // 118 // 摘要: 119 // 获取模型的值。 120 // 121 // 返回结果: 122 // 模型的值。有关 System.Web.Mvc.ModelMetadata 的更多信息,请参见 Brad Wilson 的博客上的文章 ASP.NET 123 // MVC 2 Templates, Part 2: ModelMetadata 124 public object Model { get; set; } 125 // 126 // 摘要: 127 // 获取模型的类型。 128 // 129 // 返回结果: 130 // 模型的类型。 131 public Type ModelType { get; } 132 // 133 // 摘要: 134 // 获取或设置要为 null 值显示的字符串。 135 // 136 // 返回结果: 137 // 要为 null 值显示的字符串。 138 public virtual string NullDisplayText { get; set; } 139 // 140 // 摘要: 141 // 获取或设置一个值,该值表示当前元数据的顺序。 142 // 143 // 返回结果: 144 // 当前元数据的顺序值。 145 public virtual int Order { get; set; } 146 // 147 // 摘要: 148 // 获取模型元数据对象的集合,这些对象描述模型的属性。 149 // 150 // 返回结果: 151 // 用于描述模型属性的模型元数据对象的集合。 152 public virtual IEnumerable<ModelMetadata> Properties { get; } 153 // 154 // 摘要: 155 // 获取属性名称。 156 // 157 // 返回结果: 158 // 属性名称。 159 public string PropertyName { get; } 160 // 161 // 摘要: 162 // 获取或设置提供程序。 163 // 164 // 返回结果: 165 // 提供程序。 166 protected ModelMetadataProvider Provider { get; set; } 167 // 168 // 摘要: 169 // 获取或设置一个值,该值指示是否启用请求验证。 170 // 171 // 返回结果: 172 // 如果启用了请求验证,则为 true;否则为 false。 173 public virtual bool RequestValidationEnabled { get; set; } 174 // 175 // 摘要: 176 // 获取或设置短显示名称。 177 // 178 // 返回结果: 179 // 短显示名称。 180 public virtual string ShortDisplayName { get; set; } 181 // 182 // 摘要: 183 // 获取或设置一个值,该值指示属性是否应显示在只读视图(如列表和详细信息视图)中。 184 // 185 // 返回结果: 186 // 如果应在只读视图中显示模型,则为 true;否则为 false。 187 public virtual bool ShowForDisplay { get; set; } 188 // 189 // 摘要: 190 // 获取或设置一个值,该值指示是否应在可编辑视图中显示模型。 191 // 192 // 返回结果: 193 // 如果应在可编辑视图中显示模型,则为 true;否则为 false。 194 public virtual bool ShowForEdit { get; set; } 195 // 196 // 摘要: 197 // 获取或设置模型的简单显示字符串。 198 // 199 // 返回结果: 200 // 模型的简单显示字符串。 201 public virtual string SimpleDisplayText { get; set; } 202 // 203 // 摘要: 204 // 获取或设置一个提示,该提示建议要为此模型使用哪个模板。 205 // 206 // 返回结果: 207 // 一个提示,建议要为此模型使用哪个模板。 208 public virtual string TemplateHint { get; set; } 209 // 210 // 摘要: 211 // 获取或设置可用作水印的值。 212 // 213 // 返回结果: 214 // 水印。 215 public virtual string Watermark { get; set; } 216 217 // 摘要: 218 // 从模型的 System.Linq.Expressions.Expression 参数返回元数据。 219 // 220 // 参数: 221 // expression: 222 // 一个标识模型的表达式。 223 // 224 // viewData: 225 // 视图数据字典。 226 // 227 // 类型参数: 228 // TParameter: 229 // 参数的类型。 230 // 231 // TValue: 232 // 值的类型。 233 // 234 // 返回结果: 235 // 元数据。 236 public static ModelMetadata FromLambdaExpression<TParameter, TValue>(Expression<Func<TParameter, TValue>> expression, ViewDataDictionary<TParameter> viewData); 237 // 238 // 摘要: 239 // 从模型的表达式参数中获取元数据。 240 // 241 // 参数: 242 // expression: 243 // 一个标识模型的表达式。 244 // 245 // viewData: 246 // 视图数据字典。 247 // 248 // 返回结果: 249 // 模型的元数据。 250 public static ModelMetadata FromStringExpression(string expression, ViewDataDictionary viewData); 251 // 252 // 摘要: 253 // 获取模型的显示名称。 254 // 255 // 返回结果: 256 // 模型的显示名称。 257 public string GetDisplayName(); 258 // 259 // 摘要: 260 // 返回模型的简单说明。 261 // 262 // 返回结果: 263 // 模型的简单说明。 264 protected virtual string GetSimpleDisplayText(); 265 // 266 // 摘要: 267 // 获取模型的验证程序的列表。 268 // 269 // 参数: 270 // context: 271 // 控制器上下文。 272 // 273 // 返回结果: 274 // 模型的验证程序的列表。 275 public virtual IEnumerable<ModelValidator> GetValidators(ControllerContext context); 276 }
这个类定义了有很多的属性,下面分别分组介绍:
a. 基本属性
1 public Type ContainerType { get; } 2 public virtual bool IsComplexType { get; } 3 public bool IsNullableValueType { get; } 4 public object Model { get; set; } 5 public Type ModelType { get; } 6 public string PropertyName { get; }
ContainerType表示容器的类型, 对对象类型本身,无类型定义包括它,其ContainerType是null, 其属性的ModelMetadata的ContainerType是对象类型
IsComplexType表示是否复杂类型, 判断的依据是是否与字符串进行转换, return !(TypeDescriptor.GetConverter(ModelType).CanConvertFrom(typeof(string));
IsNullableValueType 表示是否可空值类型
Model 表示当前的模型对象
ModelType 表示Model的类型
PropertyName 表示属性的名称,对应属性元数据时
1 protected ModelMetadataProvider Provider { get; set; }
表示元数据提供者
1 public virtual Dictionary<string, object> AdditionalValues 2 { 3 get { return _additionalValues; } 4 }
表示定义的附加的元数据,通过System.Web.Mvc.AdditionalMetadataAttribute实现,该属性实现IMetadataAware接口,在ModelMetadata对象创建后添加元数据到AdditionValues集合。
b. 定制元数据信息
1)UIHintAttribute 声明模板名称,对应ModelMetadata的TemplateHint属性
2)HiddenInputAttribute声明显示为将属性值呈现为hidden元素,同时属性值显示为只读,通过其DisplayValue可隐藏显示,
对应ModelMetadata两个属性:TemplateHint和HideSurroundingHtml, 注意UIHintAttribute设置具有更高的优先级
3)ScaffoldColumnAttribute声明元素是否呈现在html中,对应ModelMetadata的ShowForDisplay和ShowForEdit属性
4)DateTypeAttribute 对应ModelMetadata的DataTypeAttribute
5)DisplayFormat 对应ModelMetadata的ConvertTEmptyStringToNull, NullDisplayText,DisplayFormatString, EditFormatString
6)EditableAttribute和ReadonlyAttribute 对应ModelMetadata的IsReadOnly
7)DisplayAttribute和DisplayNameAttribute 对应ModelMetadata的DisplayName, ShortDisplayName, Description, Order, Watermark
8)RequiredAttribute 对应ModelMetadata的IsRequired
9)AllowHtmlAttribute 对应ModelMetadata的RequestValidationEnabled
二.元数据提供机制ModelMetadataProvider
ModelMetadata提供机制是通过ModelMetadataProvider来实现, ModelMetadataProvider是一个抽象类,定义如下:
1 public abstract class ModelMetadataProvider 2 { 3 public abstract IEnumerable<ModelMetadata> GetMetadataForProperties(object container, Type containerType); 4 5 public abstract ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, Type containerType, string propertyName); 6 7 public abstract ModelMetadata GetMetadataForType(Func<object> modelAccessor, Type modelType); 8 }
在ASP.NET MVC元数据提供入口是ModelMetadataProviders类,实现代码如下:
1 public class ModelMetadataProviders 2 { 3 private static ModelMetadataProviders _instance = new ModelMetadataProviders(); 4 private ModelMetadataProvider _currentProvider; 5 private IResolver<ModelMetadataProvider> _resolver; 6 7 internal ModelMetadataProviders(IResolver<ModelMetadataProvider> resolver = null) 8 { 9 _resolver = resolver ?? new SingleServiceResolver<ModelMetadataProvider>( 10 () => _currentProvider, 11 new CachedDataAnnotationsModelMetadataProvider(), 12 "ModelMetadataProviders.Current"); 13 } 14 15 public static ModelMetadataProvider Current 16 { 17 get { return _instance.CurrentInternal; } 18 set { _instance.CurrentInternal = value; } 19 } 20 21 internal ModelMetadataProvider CurrentInternal 22 { 23 get { return _resolver.Current; } 24 set { _currentProvider = value ?? new EmptyModelMetadataProvider(); } 25 } 26 }
从中我们看到框架默认的元数据提供类型是CachedDataAnnotationsModelMetadataProvider, 整个交互的类图如下: