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 类型

时间: 2024-10-17 20:40:29

Model元数据解析的相关文章

ASP.NET MVC中Model元数据解析学习

闲来继续学习蒋金楠大师的ASP.NET MVC框架揭秘一书,当前主要阅读的内容是Model元数据的解析,即使是阅读完的现在,仍然有不少细节不是特别明白.好在这部分内容主要是关于Razor引擎的呈现的,通过注解的方式对Model进行自定的修饰,最终使得页面在渲染时(即从cshtml文件转化为html时),相关的数据能够按照指定的形式转化并显示.由于接下来的项目中不再打算使用Razor引擎,该引擎虽然很不错,但也有一些问题,例如存在HTML5代码与HtmlHelper的混写,使得UI层很难与业务代码

ASP.NET MVC Model元数据(四)

ASP.NET MVC Model元数据(四) 前言 前面的篇幅讲解了Model元数据生成的过程,并没有对Model元数据生成过程的内部和Model元数据结构的详细解释.看完本篇后将会对Model元数据有更清楚的了解,当然了也不会是特别全面的,因为后面还有篇幅.希望能给大家带来好的效果. Model元数据 什么是Model元数据? 生成Model元数据的过程[一] 生成Model元数据的过程[二] ModelMetaData的定义.详解 Model元数据应用(常用特性应用)-1 Model元数据

asp.net Model元数据学习三

5.Model元数据的提供机制 表示Model元数据的ModelMetadata对象最终是通过一个名为ModelMetadataProvider对象提供的,Model元数据的提供机制是以ModelMetadataProvider为核心的.我们首先来看ModelMetadata的构造函数: public ModelMetadata(ModelMetadataProvider provider, Type containerType, Func<object> modelAccessor,Type

MVC之Model元数据

Contronoller激活之后,ASP.NET MVC会根据当前请求上下文得到目标Action的名称,然后解析出对应的方法并执行之. 在整个Action方法的执行过程中,Model元数据的解析是一个非常重要的环节.ASP.NET MVC中的Model实际上View Model,表示最终绑定到View上的数据,而Model元数据描述了Model的数据结构,以及Model的每个数据成员的一些特性. 正是有了Model元数据的存在,才使模板化HTML的呈现机制成为可能.此外,Model元数据支撑了A

ASP.NET MVC Model元数据(三)

ASP.NET MVC Model元数据(三) 前言 在上篇中我们大概的讲解了Model元数据的生成过程,并没有对Model元数据本身和详细的生成过程有所描述,本篇将会对详细的生成过程进行讲解,并且会对Model元数据本身的结构稍作讲解,读完本篇过后你将会对Model元数据的结构有个很清晰的印象. Model元数据 什么是Model元数据? 生成Model元数据的过程[一] 生成Model元数据的过程[二] ModelMetaData的定义.详解 Model元数据应用(常用特性应用)-1 Mod

ASP.NET MVC Model元数据(五)

ASP.NET MVC Model元数据(五) 前言 在上一篇中我们描述了应用于Model上面的各种用于显示控制的特性类,在本篇中将详细的介绍这些特性类的应用,虽然它们跟Model元数据的直接关系并不大,但是我们可以用它们在编码阶段控制运行时的显示. Model元数据 什么是Model元数据? 生成Model元数据的过程[一] 生成Model元数据的过程[二] ModelMetaData的定义.详解 Model元数据应用(常用特性应用)-1 Model元数据应用(自定义视图模板)-2 Model

ASP.NET MVC Model元数据(一)

ASP.NET MVC Model元数据(一) 前言 在我初学的时候对Model元数据的概念很模糊,或者说是在大脑中没有它的一个模型,作为小白的我去看网上的一些文章还是两眼一黑啥都看不明白,然后我想退缩了,对的我退缩了准备跳过这个部分去学其他的,在这过程中干什么都没精神,就跟有一根刺插在心上一样,最终我还是回头了,现在来和大家分享一下什么是Model元数据,希望看完能对有的朋友有点帮助,大概的了解一下Model元数据到底是个什么玩意. Model元数据 什么是Model元数据? 生成Model元

【笔记】ASP.NET MVC Model元数据

问题1:什么叫Model元数据? Model元数据,是针对数据类型的一种描述信息.由于复杂类型(或者说类型嵌套的存在,比如CustomerModel中有一个属性为复杂类型Address)的存在,因此Model 元数据为树形结构: 1 //namespace:System.Web.Mvc 2 public class ModelMetadata 3 { 4 //其它成员 5 6 //当前模型类型 7 //倘若用数据库中树形结构解释,这个属性相当于Id 8 public Type ModelType

Model元数据提供机制小结

在最开始先我得说说我看这部分的情况,最开始被各种ModelMetadata和各种ModelMetadataProvider给搞晕了,就几页书花了我好大的精力去看,直到后来看了一幅类图,细细看各个类之间的关系,重新阅读这部分的内容,我才算有所了解,有所收获,这个估计是以后看书的方法,看代码的方法,先了解结构,才不会被庞大的类库所混乱.那么我也首先把类图列出来,这幅图依据我个人喜好位置上作了调整,与书上的不同. 整张图左边是ModelMetadata部分的,右边才是元数据的提供者Provider,虽