Model元数据解析
- Model 元数据是针对数据类型的一种描述信息,主要用于控制数据类型本身及其成员属性在界面上的呈现方式,同时也为Model 绑定和验证提供必不可少的元数据信息。一个复杂数据类型通过属性的方式定义了一系列的数据成员,而Model 元数据不仅仅是数据类型本身的描述,对数据成员的描述也包含其中,所以Model 元数据具有一个层次化结构。
- AdditionalMetadataAttribute定义的值放在元数据的AdditionalValues中.实现接口IMetadat aAware
- ModelMetadata包含几个重要的属性ModelType,IsComplexType,IsNullableValueType,ContainerType,PropertyName,Model
- IsComplexType
判断某个类型是否是复杂类型的条件只有一个,即是否允许字符串类型向该类型的转换。所以所有的基元类型C Primative Type) 和可空值类型CNullable Type) 均不是复杂类型。对于一个默认为复杂类型的自定义数据类型,可以在它上面应用TypeConverterAttribute 特性并指定一个支持字符串转换的TypeConverter 类型,使之转变成简单类型。
- UIHintAttribute
ModelMetadata 的TemplateHint 属性可以通过UIHintAttribute 特性来定制.指定要使用的模板. (UIHintImplementation).多个的时候,要区分优先级.
- HiddenInputAttribute
HiddenInputAttribute 特性Mode lMetadata 对象的TemplateHint 属性设置为"HiddenI nput",其HideSurroundingHtrnl 属性则对应着HiddenInpu tAttribute 的DisplayValue 属性。UIHintAttribute 具有更高的优先级。
- ScaffoldColumnAttribute
具有一个布尔类型的只读属性Scaffold表示目标元素是否应该存在于呈现在最终生成的HTML 的基架中,HiddenInputAttribute 是隐藏的,但是包含在HTML中.
ScaffoldColumnAttribute 最终用于控制ModelMetadata 的ShowForDisplay 和ShowForEdit属性
- Data TypeAttribute控制显示格式,如Email.DisplayFormatAttribute
其中DataTypeAttribute 中设置的数据类型对应于ModelMetadata 的DataTypeName
属性,而DisplayF ormatAttribute 的ConvertEmp可S位ingToNull 和NullDisplayText 属性对应着ModelMetadata 的同名属性。DataTypeAttribute可以继承自定义格式
- EditableAttribute ReadOnlyAttribute
- Display DisplayNameAttribute
- RequiredAttribute
- IMetadataAware,通过实现此接口可以实现对元数据的定制,接口中只有一个方法 void OnMetadataCreated(ModelMetadata metadata);
- 当Model 元数据被创建出来后,上述的这一系列数据注解特性会被提取出来对其进行初始化,然后获取应用在目标元素上所有实现了IMetadataAware 接口的特性,并将初始化的ModelMetadata 对象作为参数调用OnMetadataCreated 方法。通过自定义实现该接口的特性不仅仅可以添加一些额外的元数据属性,还可以修改己经通过相应的标注特性初始化的相关属性。
- ModelMetadata 的RequestValidationEnabled 属性开启/关闭请求验证的开关。该属性在默认情况下为True ,意味着默认开启针对HTI\在L 标记的请求验证。
- AllowHtmlAttribute metadata.RequestValidationEnabled = false;
- 自定义的控件模板要放在Share下或者Controller对应的View中的EditorTemplates文件夹下.可以理解为,一般的页面也是对应的Model的模板页,两者之间的实现思路是一样的.
@model bool
<table>
<tr>
<td>@Html.RadioButton("", true, Model)</td>
<td>@Html.RadioButton("", false, Model)</td>
</tr>
</table>
- MVC内部定义了很多模板,当调用HtmlHelper.For的时候,会根据显示模式或者编辑模式和元数据找到一个显示用的模板.
- MVC预定义的模板:EmailAddress,Hiddenlnput,HTML,(Text,String效果一样),URL,MultilineText,Password,decimal,Boolean,Collection,Object
- 模板查找路径顺序
- 传入的TemplateName
- ModelMetadata的TemplateHint属性
- DataTypeName属性
- 非空类型(不是Nullable类型)用类型名作为模板View名称Nullable类型的获取真实类型作为View名称,如Int?的模板为Int32的View
- 非复杂类型,会选择String的模板,然后退出检索,否则下一步
- 如果声明是接口,
- 如果继承IEnumerable采用Collection模板
- 选择Object模板
- ,然后退出检索,否则下一步
- 向父类追溯,选择各级父类的名称作为模板
- 直到Object类型,如果实现Ienumerable,则选择Collection代替Object.
- 查找的源代码
internal static IEnumerable<string> GetViewNames(ModelMetadata metadata, params string[] templateHints)
{ foreach (string templateHint in templateHints.Where(s => !String.IsNullOrEmpty(s))) { yield return templateHint; } // We don't want to search for Nullable<T>, we want to search for T (which should handle both T and Nullable<T>) Type fieldType = Nullable.GetUnderlyingType(metadata.RealModelType) ?? metadata.RealModelType; // TODO: Make better string names for generic types yield return fieldType.Name; if (!metadata.IsComplexType) { yield return "String"; } else if (fieldType.IsInterface) { if (typeof(IEnumerable).IsAssignableFrom(fieldType)) { yield return "Collection"; } yield return "Object"; } else { bool isEnumerable = typeof(IEnumerable).IsAssignableFrom(fieldType); while (true) { fieldType = fieldType.BaseType; if (fieldType == null) { break; } if (isEnumerable && fieldType == typeof(Object)) { yield return "Collection"; } yield return fieldType.Name; } } }
- 优先使用自定义的模板,路径是"DisplayTemplate/{TemplateName}"和"EditorTemplate/{TemplateName}",找不到的时候在默认的模板中查找
- 系统默认的模板
- 编辑系统模板
private static readonly Dictionary<string, Func<HtmlHelper, string>> _defaultEditorActions = new Dictionary<string, Func<HtmlHelper, string>>(StringComparer.OrdinalIgnoreCase) { { "HiddenInput", DefaultEditorTemplates.HiddenInputTemplate }, { "MultilineText", DefaultEditorTemplates.MultilineTextTemplate }, { "Password", DefaultEditorTemplates.PasswordTemplate }, { "Text", DefaultEditorTemplates.StringTemplate }, { "Collection", DefaultEditorTemplates.CollectionTemplate }, { "PhoneNumber", DefaultEditorTemplates.PhoneNumberInputTemplate }, { "Url", DefaultEditorTemplates.UrlInputTemplate }, { "EmailAddress", DefaultEditorTemplates.EmailAddressInputTemplate }, { "DateTime", DefaultEditorTemplates.DateTimeInputTemplate }, { "Date", DefaultEditorTemplates.DateInputTemplate }, { "Time", DefaultEditorTemplates.TimeInputTemplate }, { typeof(byte).Name, DefaultEditorTemplates.NumberInputTemplate }, { typeof(sbyte).Name, DefaultEditorTemplates.NumberInputTemplate }, { typeof(int).Name, DefaultEditorTemplates.NumberInputTemplate }, { typeof(uint).Name, DefaultEditorTemplates.NumberInputTemplate }, { typeof(long).Name, DefaultEditorTemplates.NumberInputTemplate }, { typeof(ulong).Name, DefaultEditorTemplates.NumberInputTemplate }, { typeof(bool).Name, DefaultEditorTemplates.BooleanTemplate }, { typeof(decimal).Name, DefaultEditorTemplates.DecimalTemplate }, { typeof(string).Name, DefaultEditorTemplates.StringTemplate }, { typeof(object).Name, DefaultEditorTemplates.ObjectTemplate }, };
- 编辑系统模板
- 显示系统模板
private static readonly Dictionary<string, Func<HtmlHelper, string>> _defaultDisplayActions = new Dictionary<string, Func<HtmlHelper, string>>(StringComparer.OrdinalIgnoreCase) { { "EmailAddress", DefaultDisplayTemplates.EmailAddressTemplate }, { "HiddenInput", DefaultDisplayTemplates.HiddenInputTemplate }, { "Html", DefaultDisplayTemplates.HtmlTemplate }, { "Text", DefaultDisplayTemplates.StringTemplate }, { "Url", DefaultDisplayTemplates.UrlTemplate }, { "Collection", DefaultDisplayTemplates.CollectionTemplate }, { typeof(bool).Name, DefaultDisplayTemplates.BooleanTemplate }, { typeof(decimal).Name, DefaultDisplayTemplates.DecimalTemplate }, { typeof(string).Name, DefaultDisplayTemplates.StringTemplate }, { typeof(object).Name, DefaultDisplayTemplates.ObjectTemplate }, };
- 自定义模板查找路径
private static readonly Dictionary<DataBoundControlMode, string> _modeViewPaths = new Dictionary<DataBoundControlMode, string> { { DataBoundControlMode.ReadOnly, "DisplayTemplates" }, { DataBoundControlMode.Edit, "EditorTemplates" } };
- 一个类型的值为null时,不能调用GetType()方法.没有实体,这是个实例方法
- Nullable类型调用GetType时,返回值是真实的类型T.
- Type.IsGenericTypeDefinition获取泛型类型是否是泛型定义,还是具体的泛型.GetGenericTypeDefinition获取泛型对应的定义.GetGenericArguments获取泛型的泛型参数类型
- ModelMetadataProvider元数据提供机制
- DataAnnotationsModelMetadata
- System.Web.Mvc.CachedDataAnnotationsModelMetadata 才是默认使用的ModelMetadata 类型
- Provider创建ModelMetadata的过程,创建属性的modelmetadata.先找特性,创建modelmetadata,应用IMetadataAware的特性,因此他的优先级更高.
protected virtual ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, Type containerType, PropertyDescriptor propertyDescriptor)
{ IEnumerable<Attribute> attributes = FilterAttributes(containerType, propertyDescriptor, propertyDescriptor.Attributes.Cast<Attribute>()); ModelMetadata result = CreateMetadata(attributes, containerType, modelAccessor, propertyDescriptor.PropertyType, propertyDescriptor.Name); ApplyMetadataAwareAttributes(attributes, result); return result; } - ModelMetadataProviders 具有一个ModelMetadataProvider类型 的静态可读可写属性Current 用于获取和设置当前使用的ModelMetadataP rovider 。在默认情况下, Current 属性返回的就是一个CachedDataAnnotationsModelMetadataProvider 对象。
- ControllerBase中有一个ViewData对象,用于向View传递数据.ViewData中有一个ModelMetadata元数据对象
- ASPNETMVC 具有一个可扩展的以Mode lM etadataProvider 为核心的Model 元数据提供系统,默认采用的ModelMetadataProvider 类型为CachedDataAnnotationsModelMetadataProvider.
- System.Web.Mvc.CachedDataAnnotationsModelMetadata 才是默认使用的ModelMetadata 类型
Model元数据解析的更多相关文章
- Artech的MVC4框架学习——第四章Model元数据的解析
总结: 第一Model元数据是针对 数据类型的一种表述信息. 第二Model元数据作用:控制数据类型本身及其成员,通过相应的特性,在view中 为绑定的数据(Model)实现模版化的html呈现. 第 ...
- ASP.NET MVC Model元数据(四)
ASP.NET MVC Model元数据(四) 前言 前面的篇幅讲解了Model元数据生成的过程,并没有对Model元数据生成过程的内部和Model元数据结构的详细解释.看完本篇后将会对Model元数 ...
- .NET/ASP.NETMVC Model元数据、HtmlHelper、自定义模板、模板的装饰者模式(一)
.NET/ASP.NETMVC Model元数据.HtmlHelper.自定义模板.模板的装饰者模式(一) 阅读目录: 1.开篇介绍 2.Model与View的使用关系(数据上下文DataContex ...
- MVC之Model元数据
Contronoller激活之后,ASP.NET MVC会根据当前请求上下文得到目标Action的名称,然后解析出对应的方法并执行之. 在整个Action方法的执行过程中,Model元数据的解析是一个 ...
- ASP.NET MVC Model元数据(五)
ASP.NET MVC Model元数据(五) 前言 在上一篇中我们描述了应用于Model上面的各种用于显示控制的特性类,在本篇中将详细的介绍这些特性类的应用,虽然它们跟Model元数据的直接关系并不 ...
- ASP.NET MVC Model元数据(三)
ASP.NET MVC Model元数据(三) 前言 在上篇中我们大概的讲解了Model元数据的生成过程,并没有对Model元数据本身和详细的生成过程有所描述,本篇将会对详细的生成过程进行讲解,并且会 ...
- ASP.NET MVC Model元数据(二)
ASP.NET MVC Model元数据(二) 前言 在上篇中,给大家留个对Model元数据的印象,并没有对Model元数据有过多的讲解,而在本篇中也不会对Model元数据的本身来解释,而是针对于它的 ...
- ASP.NET MVC Model元数据(一)
ASP.NET MVC Model元数据(一) 前言 在我初学的时候对Model元数据的概念很模糊,或者说是在大脑中没有它的一个模型,作为小白的我去看网上的一些文章还是两眼一黑啥都看不明白,然后我想退 ...
- .NET/ASP.NETMVC 大型站点架构设计—迁移Model元数据设置项(自定义元数据提供程序)
阅读目录: 1.需求背景介绍(Model元数据设置项应该与View绑定而非ViewModel) 1.1.确定问题域范围(可以使用DSL管理问题域前提是锁定领域模型) 2.迁移ViewModel设置到外 ...
随机推荐
- Week8 软件规格说明书
1.概述 本项目组所开发的软件为一个基于Android的手机端的时间管理软件,主要功能为时间管理软件,可以用于管理待办事项,记录一些需要提醒的信息等.有事件提醒.与Google账户同步.课程表等功能. ...
- Netsharp快速入门(之8) 基础档案(工作区2 设置商品主列表、规格细列表、商品表单、查询)
作者:秋时 杨昶 时间:2014-02-15 转载须说明出处 3.5.1.1 列表设置 1.选择第一行主列表,点工具-列表方案 2.打开列表方案界面后,在列表项目填入需要用到实体Demo.Arc ...
- 使用Java 8 API,根据传递的分隔符,连接list中所有的元素
public class MethodReferenceDemo1 { @FunctionalInterface interface StringListFormatter { String form ...
- MySQL中表格各页面的注意和操作项
- Visual Studio快捷键设置
1.查看当前快捷键:环境-键盘-按快捷键2.文本编辑器-C#-显示-行号3.文本编辑器-C#-制表符-插入空格4.文本编辑器-所有语言-没有选定内容时对空行应用剪切或复制命令5.Ctrl+Shift- ...
- discuzx完全自定义设计模板门户首页,栏目,专题模板方法
第一种:门户首页模板(index.htm,保存于templatedefaultportal) <!--{subtemplate common/header}--> <style id ...
- 编译libcore-amr静态库
在此链接下 https://github.com/feuvan/opencore-amr-iOS 下载它的源码到本地, 然后cd到此目录下,在终端输入命令./build_ios_xcode6.sh,便 ...
- jQuery新的事件绑定机制on()
浏览jQuery的deprecated列表,发现live()和die()在里面了,赶紧看了一下,发现从jQuery1.7开始,jQuery引入了全新的事件绑定机制,on()和off()两个函数统一处理 ...
- doctype声明、浏览器的标准、怪异等模式
doctype 标准(严格)模式(Standards Mode).怪异(混杂)模式(Quirks Mode),如何触发,区分他们有何意义? 触发标准模式 1.加DOCTYPE声明,比如:<!DO ...
- java输出流实现文件下载
//导出Excel try { HSSFWorkbook wb = carService.export(list); //调用service方法~! response.setContentType(& ...