• 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元数据解析的更多相关文章

  1. Artech的MVC4框架学习——第四章Model元数据的解析

    总结: 第一Model元数据是针对 数据类型的一种表述信息. 第二Model元数据作用:控制数据类型本身及其成员,通过相应的特性,在view中 为绑定的数据(Model)实现模版化的html呈现. 第 ...

  2. ASP.NET MVC Model元数据(四)

    ASP.NET MVC Model元数据(四) 前言 前面的篇幅讲解了Model元数据生成的过程,并没有对Model元数据生成过程的内部和Model元数据结构的详细解释.看完本篇后将会对Model元数 ...

  3. .NET/ASP.NETMVC Model元数据、HtmlHelper、自定义模板、模板的装饰者模式(一)

    .NET/ASP.NETMVC Model元数据.HtmlHelper.自定义模板.模板的装饰者模式(一) 阅读目录: 1.开篇介绍 2.Model与View的使用关系(数据上下文DataContex ...

  4. MVC之Model元数据

    Contronoller激活之后,ASP.NET MVC会根据当前请求上下文得到目标Action的名称,然后解析出对应的方法并执行之. 在整个Action方法的执行过程中,Model元数据的解析是一个 ...

  5. ASP.NET MVC Model元数据(五)

    ASP.NET MVC Model元数据(五) 前言 在上一篇中我们描述了应用于Model上面的各种用于显示控制的特性类,在本篇中将详细的介绍这些特性类的应用,虽然它们跟Model元数据的直接关系并不 ...

  6. ASP.NET MVC Model元数据(三)

    ASP.NET MVC Model元数据(三) 前言 在上篇中我们大概的讲解了Model元数据的生成过程,并没有对Model元数据本身和详细的生成过程有所描述,本篇将会对详细的生成过程进行讲解,并且会 ...

  7. ASP.NET MVC Model元数据(二)

    ASP.NET MVC Model元数据(二) 前言 在上篇中,给大家留个对Model元数据的印象,并没有对Model元数据有过多的讲解,而在本篇中也不会对Model元数据的本身来解释,而是针对于它的 ...

  8. ASP.NET MVC Model元数据(一)

    ASP.NET MVC Model元数据(一) 前言 在我初学的时候对Model元数据的概念很模糊,或者说是在大脑中没有它的一个模型,作为小白的我去看网上的一些文章还是两眼一黑啥都看不明白,然后我想退 ...

  9. .NET/ASP.NETMVC 大型站点架构设计—迁移Model元数据设置项(自定义元数据提供程序)

    阅读目录: 1.需求背景介绍(Model元数据设置项应该与View绑定而非ViewModel) 1.1.确定问题域范围(可以使用DSL管理问题域前提是锁定领域模型) 2.迁移ViewModel设置到外 ...

随机推荐

  1. Ubuntu14.04搭建LAMP环境

    安装Apache2                                                             sudo apt-get install apache2   ...

  2. 11.5Daily Scrum

    人员 任务分配完成情况 明天任务分配 王皓南 实现网页上视频浏览的功能.研究相关的代码和功能.811 数据库测试 申开亮 实现网页上视频浏览的功能.研究相关的代码和功能.812 实现视频浏览的功能 王 ...

  3. xcode 使用通用总结

    一.搜索东西 有时候类很多,方法很多,想改某类时,还要打开各自文件夹去点进去,感觉很麻烦费时间. 如下图:用此搜索可以搜到此类,从而进行修改. 有时候想在类中找某个方法或者属性,自已一点一点找很费劲, ...

  4. 笔记本显示器坏了,从硬盘安装win7系统

    可以装的,从硬盘安装的话,步骤如下:一.将从网上下载的win7旗舰版ISO系统文件存放到D盘. 二.从网上下载虚拟光驱,打开安装后在任务栏右通知区显示“虚拟DAEMON管理器”图标,在我的电脑窗口显示 ...

  5. java加载机制整理

    本文是根据李刚的<疯狂讲义>作的笔记,程序有的地方做了修改,特别是路径,一直在混淆,浪费了好多时间!!希望懂的同学能够指导本人,感激尽............ 1.jvm 和 类的关系 当 ...

  6. boost环境搭建

    切换到boost目录下面,使用编译命令>bjam.exe --with-date_time --toolset=msvc-9.0 --build-type=complete stage --wi ...

  7. [REFERENCE] Real-Time-Normal-Map-Dxt-Compression

    DXT5N & 3Dc(aka BC5) compression in common code & SIMD: http://mrelusive.com/publications/pa ...

  8. js中常用数组方法concat join push pop slice splice shift

    javascript给我们很多常用的 数组方法,极大方便了我们做程序.下面我们来介绍下常用的集中数组方法. 比如 concat() join() push() pop() unshift() shif ...

  9. C内联汇编

    用C写程序比直接用汇编写程序更简洁,可读性更好,但效率可能不如汇编程序,因为C程序毕竟要经由编译器生成汇编代码,尽管现代编译器的优化已经做得很好了,但还是不如手写的汇编代码.另外,有些平台相关的指令必 ...

  10. iOS音效

    //AudioToolbox.framework是一套基于C语言的框架,使用它来播放音效其本质是将短音频注册到系统声音服务(System Sound Service) //System Sound S ...