• 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. NABC的特点分析

    题目:                         请把采用卡片分类的方法讨论你们的团队开发项目特点,再按照 NABC 的框架分析每个特点. 每一个组员针对其中的一个特点将NABC的分析结果发表博 ...

  2. 用Keytool和OpenSSL生成和签发数字证书

    一)keytool生成私钥文件(.key)和签名请求文件(.csr),openssl签发数字证书      J2SDK在目录%JAVA_HOME%/bin提供了密钥库管理工具Keytool,用于管理密 ...

  3. Python编码设置

    系统编码顺序: 1, a.encode(sys.stdout.encoding) 2, a.encode(default_string) sys.stdout.encoding里的值可以用环境变量PY ...

  4. 1566: [NOI2009]管道取珠 - BZOJ

    Description Input第一行包含两个整数n, m,分别表示上下两个管道中球的数目. 第二行为一个AB字符串,长度为n,表示上管道中从左到右球的类型.其中A表示浅色球,B表示深色球. 第三行 ...

  5. 简述负载均衡&CDN技术

    曾经见到知乎上有人问“为什么像facebook这类的网站需要上千个工程师维护?”,下面的回答多种多样,但总结起来就是:一个高性能的web系统需要从无数个角度去考虑他,大到服务器的布局,小到软件中某个文 ...

  6. bzoj 1565 最大权闭合子图

    因为每个植物都有保护的点(每排相邻的右面的算是保护左面的),所以连他和保护 的点一条边,然后每个点有自己的权值,要找到最大的权值且满足每个点在访问时他 的前驱一定被访问,那么反向建边,转化为后继必须访 ...

  7. 【BZOJ】【4034】【HAOI2015】T2

    树链剖分/dfs序 树上单点修改+子树修改+链查询 其实用dfs序做也可以…… 其实树链剖分就是一个特殊的dfs序嘛= =所以树链剖分也可以搞子树-(Orz ZYF) 至于为什么……你看在做剖分的时候 ...

  8. DXGI_FORMAT_R8G8B8A8_UNORM_SRGB

    这个类型的resource 后面多个SRGB 表示SRGB空间是指gamma 矫正系数为2.2的色彩空间,这个问题我没有问别人,是我自己是上网查的,我觉得我不是个女人了......我又level up ...

  9. nginx+php+flight 构建RESTFul API

    配置: Nginx: conf目录下nginx.conf配置文件. 第44行改为:root   D:/wwwroot/www; 第45行改为:index  index.html index.htm i ...

  10. C#顺序表(数据结构)

    xmfdsh我近来心情实在不好,只因为这两天课比较少,然后一下子时间太多,不知道干什么,心情郁闷......这是要闹哪样?这都让我一个郁闷了一个晚上.闲来无聊,回顾下之前学的C#数据结构,数据结构的重 ...