模型与元数据(Model & Model Metadata)

ASP.NET MVC中有一个模型的概念,实际上模型就是一个类型,Model表示的就是最终要绑定到View视图页面上的数据而已。

模型元数据

模型元数据用ModelMetadata类表示,它描述Model自身的类型、成员的类型、自身和成员的特性等信息,它的作用有两点:1.控制模型在视图上的呈现方式。2.为模型绑定验证逻辑。ModelMetadata元数据对象描述了与它关联在一起的Model的数据结构,以及Model的每个数据成员的一些特性。正是有了Model元数据的存在,才使模板化HTML的呈现机制成为可能。要创建一个模型的元数据,只需要在ModelMetadata构造函数中将Model的类型作为参数传递进去即可。ModelMetadata支撑了ASP.NET MVC的Model验证体系,因为针对Model的验证规则正是定义在Model元数据中。

//ModelMetadata的成员
    
ModelMetadata ( ModelMetadataProvider provider , Type containerType , Func<object> modelAccessor , Type modelType , string propertyName );
//构造函数,传递Model的类型作为参数创建出Model的元数据对象
   
Provider 
//Model元数据的提供程序。

ModelType
//模型的类型。

IsComplexType
//是否是复杂类型。复杂类型即不是基元类型和值类型的引用类型
//如果Model支持从基元字符串转换为类类型,则IsComplexType将为fale,这可以通过TypeConverterAttribute特性描述当前Model是否可由字符串转为为Model类型
//如果是,则IsComplexType返回false
//示例:
[ TypeConverter ( typeof ( AnimalTypeConvert ) )]
public class Animal
{
    public string Name { get; set; }
}

public class AnimalTypeConvert : System.ComponentModel.TypeConverter
{
    public override bool CanConvertFrom ( ITypeDescriptorContext context , Type sourceType )
    {
        return sourceType == typeof ( string );
    }

public override object ConvertFrom ( ITypeDescriptorContext context , CultureInfo culture , object value )
    {
        if ( value is string )
        {
            Animal a = new Animal { Name = value.ToString ( ) };
            return a;
        }
        return base.ConvertFrom ( context , culture , value );
    }
}

//测试:
string animal = "蚂蚁";
AnimalTypeConvert AnimalTypeConvert = new AnimalTypeConvert ( );
Animal a = ( Animal ) AnimalTypeConvert.ConvertFrom ( animal );
string name = a.Name; //print 蚂蚁

IsNullableValueType
//如果该类型可为 null,则为 true;否则为 false
    
ContainerType
//包容当前类型的类型,比如Animal包含Person类型,则Person的ContainerType为Animal
    
IsReadOnly
//该模型是否是只读的
    
IsRequired
//如果该模型是必需的,则为 true;否则为 false。
        
PropertyName
//模型的名称
    
Properties
//用于描述模型属性的模型元数据对象的集合。

AdditionalValues
//包含有关模型的其他元数据的字典,可通过在模型或模型成员上运用System.Web.Mvc.AdditionalMetadataAttribute特性来为它们增加自定义用于描述信息的属性
    
TemplateHint
//一个提示,建议要为此模型使用哪种模板。

FromLambdaExpression<TParameter, TValue> ( Expression<Func<TParameter , TValue>> expression , ViewDataDictionary<TParameter> viewData );
//从模型的 System.Linq.Expressions.Expression 参数返回元数据
   
GetValidators ( ControllerContext context );
    //模型的验证程序的列表。

TemplateHint
//获取应用在元数据上的模板,比如Html模板、WPF模板、MVC模板,此属性可通过UIHintAttribute特性对元数据进行配置,TemplateHint的值=UIHintAttribute.UIHint

//此属性可通过HiddenInputAttribute特性对元数据进行配置,TemplateHint的值=HiddenInput
//如果同时为mox或模型成员设置了UIHintAttribute和HiddenInputAttribute,默认UIHintAttribute的优先级最高

数据注解

特性运用在模型和模型的成员上,这样可以影响模型的元数据,而元数据也提供某些属性与特性进行关联。也即如果将某个类型放进ModelMetadata的构造函数就可以创建出该模型的元数据对象,这个对象提供一些属性或方法可以获取该模型的元数据信息。

UIHintAttribute特性

作用:ModelMetadata的TemplateHint属性表示运用在模型上的模板,这些模板可以是Html模板、WPF模板、MVC模板等等。此属性关联在模型上指定的UIHint特性。UIHint可以在一个模型、模型成员上运用多次,在MVC框架中,展示层的类型如果是Mvc则会优先使用该UIHint,如果没有指定展示层的类型则默认使用首次出现的UIHint

UIHintAttribute ( string UIHint , string PresentationLayer )             
UIHint
//模板的名称,对应于元数据的TemplateHint属性
PresentationLayer
//展示层的类型

示例:以下创建了一个DemoModel模型,在它的成员上运用了UIHint特性,其中Bar和Baz成员运用了多次UIHint,Bar的UIHint特性使用了Mvc,所以该特性指定的模板会被确定为最终要使用的模板。

public class DemoModel
{
    public string Foo { get; set; }
    [UIHint ( "Template A" )]
    [UIHint ( "Template B" , "Mvc" )]
    public string Bar { get; set; }
    [UIHint ( "Template A" )]
    [UIHint ( "Template B" )]
    [UIHint ( "Template C" )]
    public string Baz { get; set; }
}

public class HomeController : Controller
{
    public ActionResult Index ( )
    {
        ModelMetadata modelMetadat = new ModelMetadata ( ModelMetadataProviders.Current , null , null , typeof ( DemoModel ) , null );
        return View ( modelMetadat );
    }
}

在视图中读取DemoModel的属性成员的元数据的TemplateHint信息

@model ModelMetadata

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
    <style>
        body{padding:;margin:;font:normal 12px/24px "\5FAE\8F6F\96C5\9ED1";color:#444;text-align: center;}
        table{width:500px;border:;margin:100px auto ;text-align:center;border-collapse:collapse;border-spacing:;}
        table th{background: #09007c;font-weight:normal;line-height:30px;font-size:14px;color:#FFF;}
        table tr:nth-child(odd){background:#F4F4F4;}
        table td:nth-child(even){color:#C00;}
        table tr:nth-child(5){background:#73B1E0;color:#FFF;}
        table tr:hover{background:#73B1E0;color:#FFF;}
        table td,table th{border:1px solid #EEE;}
    </style>
</head>
<body>
    <table>
        @{
            <tr>
                <th>DemoModel的属性</th>
                <th>元数据TemplateHint</th>
            </tr>
            foreach ( var p in Model.Properties )
            {
                <tr>
                    @{
                        <td>@p.PropertyName</td>
                        <td>@(p.TemplateHint??"N/A")</td>
                    }
                </tr>
            }
        }
    </table>
</body>
</html>

HiddenInputAttribute特性

作用:当使用Html.EditorFor()方法时,将运用了HiddenInput特性的模型或模型成员生成为隐藏域,HiddenInput对应于元数据的TemplateHint,而HiddenInput的DisplayValue则对应于元数据的HideSurroundingHtml。如果一个模型或模型成员上同时运用了UIHint和HiddenInput,默认UIHint的优先级更高。

//指示模型或模型成员通过Html模板生成类型为Hidden的Input元素(生成为隐藏域),对应于元数据的TemplateHint属性
HiddenInputAttribute ( bool DisplayValue ) 
DisplayValue
//一个bool值,指示该隐藏域的前面是否应以只读文本显示模型或模型成员的值,对应于元数据的HideSurroundingHtml属性

示例:使用Html.EditorFor方法将模型的成员以输入框的方式被创建,但设为隐藏域的成员将以隐藏域的方式被创建

public class DemoModel
{
    public string name { get; set; }
    [HiddenInput] //生成隐藏域且显示age的值
    public string age { get; set; }
    [HiddenInput ( DisplayValue = false )] //生成隐藏域且不显示gender的值
    public string gender { get; set; }
}
public class DefaultController : Controller
{
    public ActionResult Index()
    {
        return View ( new DemoModel { name = "sam" , age = "19" , gender = "男" } );        
    }
}

在视图页面中做测试

@model MVC.Controllers.DemoModel
<form>
    @Html.EditorFor ( m => m.name )
    @Html.EditorFor ( m => m.age )
    @Html.EditorFor ( m => m.gender )
</form>

ScaffoldColumnAttribute特性

作用:ScaffoldColumn指示当调用Html.EditorFor、Html.DisplayFor()方法创建编辑(input)、文本(label)时,运用了此特性的模型或模型成员将不会显示,也即EditorFor()、DisplayFor()方法将变得无效。经测试此特性没有效果,原因不明。ScaffoldColumn特性对应于元数据的ShowForDisplay、ShowForEdit属性。

RequiredAttribute特性

作用:使属性为必填项,与DataTypeAttribute一样,它们都派生自ValidationAttribute。

RequiredAttribute;( bool AllowEmptyStrings | string ErrorMessage |  )
AllowEmptyStrings
//获取或设置一个值,该值指示是否允许空字符串,默认false。
ErrorMessageString
//获取或设置在验证失败时显示的错误消息

DataTypeAttribute特性

作用:用于标注数据应显示的数据格式,比如时间、货币等等。

DataTypeAttribute; ( DataType dataType | string customDataType )
DataType
//一个DataType枚举,指定模型或模型成员显示的数据格式类型
CustomDataType 
//用户自定义的数据显示格式类型
DisplayFormat
//一个DisplayFormatAttribute特性,参看DisplayFormatAttribute特性
GetDataTypeName ( )
//如果需要自定义数据显示的格式类型,则通过从DataTypeAttribute派生,重写此虚方法。对应于元数据的DataTypeName属性
IsValid
//是否验证数据有效性
DisplayFormatAttribute特性
作用:格式化模型或模型成员的值
  1. DisplayFormatAttribute ( HtmlEncode | NullDisplayText | ConvertEmptyStringToNull | ApplyFormatInEditMode | DataFormatString )
  2. HtmlEncode
  3. //默认情况下,模型或模型成员的值如果包含Html则会在视图上显示时应用Html格式,此属性可指示是否需要编码Html,默认false(应用Html格式),设为true则会将Html显示为可见的字符串
  4. NullDisplayText
  5. //指示模型或模型成员的值为null时应显示的字符,对应于元数据的NullDisplayText属性
  6. ConvertEmptyStringToNull
  7. //指示模型或模型成员的值为""时,是否转换为null,对应于元数据的ConvertEmptyStringToNull属性
  8. ApplyFormatInEditMode
  9. //指示模型或模型成员的值处于编辑模式时,是否格式化模型或模型成员的值
  10. DataFormatString
  11. //搭配ApplyFormatInEditMode使用,提供在编辑模式下格式化模型或模型成员的值

DisplayAttribute特性(System.ComponentModel.DataAnnotations)

作用:为在用户界面中使用的实体类型和成员指定可本地化的字符串,这些信息是展示给用户看见的数据。类似的有DisplayNameAttribute,但后者只提供简单的功能。

  1. DisplayAttribute; (string Prompt | string Description | string Name | string ShortName | int Order | Type ResourceType  )
  2. ResourceType
  3. //本地化显示的资源文件类型,参考:多国语言的简单实现
  4. Name
  5. //为模型或模型成员设置在视图上显示的名称,也即定义别名。对应于元数据的DisplayName属性
  6. ShortName
  7. //为模型或模型成员设置在视图上显示的简短的名称,也即定义简短的别名。对应于元数据的ShortDisplayName属性
  8. Description
  9. //为模型或模型成员设置描述性文本,对应于元数据的Description属性
  10. Order
  11. //为模型或模型成员设置排序权重,默认10000。对应于元数据的Order属性
  12. Prompt
  13. //为模型或模型成员设置一个水印,此水印将会呈现在视图上
  14. GetName()
  15. //返回一个值,用于在 UI 中的字段的显示。对应于元数据的DisplayName属性
  16. GetShortName()
  17. //类似GetName方法,返回一个值,用于在UI中的字段的简洁显示。对应于元数据的ShortDisplayName属性
  18. GetDescription()
  19. //获取描述信息,对应于元数据的Description属性
  20. GetOrder()
  21. //获取对列排序所采取的顺序,默认值10000,对应于元数据的Order属性
  22. GetPrompt()
  23. //获取在UI中的水印的显示,对应于元数据的Watermark属性

例子:

  1. namespace WebErp.Controllers
  2. {
  3.     public class Animal
  4.     {
  5.         [Display(Name ="姓名")] //如果没有应用Display特性,则试图页面将显示'AnimalName'而非'姓名'
  6.         public string AnimalName { get; set; }
  7.     }
  8.     
  9.     public class DefaultController : Controller
  10.     {
  11.         public ActionResult Test()
  12.         {
  13.             return View();
  14.         }
  15.     }
  16. }
  1. @model WebErp.Controllers.Animal
  2.  
  3. <!DOCTYPE html>
  4.  
  5. <html>
  6. <head>
  7.     <meta name="viewport" content="width=device-width" />
  8.     <title>Test</title>
  9.     <style>
  10.         body{background:black;color:white;font-size:12px;font-family:Arial;}
  11.     </style>
  12. </head>
  13. <body>
  14.     <div> 
  15.         @Html.EditorForModel()
  16.     </div>
  17. </body>
  18. </html>

EditableAttribute特性(对应元数据的IsReadOnly)

作用:指示模型或模型成员是否允许被编辑

  1. EditableAttribute;(bool allowEdit)
  2. AllowEdit
  3. //是否允许编辑,对应于元数据的IsReadOnly属性

ReadOnlyAttribute特性

作用:指示模型或模型成员是否允为只读,如果同时在一个对象上运用Editable和ReadOnly,则Editable具有更高的优先级。
  1. ReadOnlyAttribute;(bool IsReadOnly)
  2. IsReadOnly
  3. //是否只读,对应于元数据的IsReadOnly属性

DisplayName特性

作用:设置属性、事件、无参函数的显示名称。在System.ComponentModel命名空间。
  1. DisplayNameAttribute;( string displayName )
  2. DisplayName
  3. //设置属性、事件、无参函数的显示名称。对应于元数据的DisplayName

在模型上应用自定义特性

IMetadataAware接口

如果将某个类型(模型)放进ModelMetadata的构造函数就可以创建出该模型的元数据对象,这个对象就代表了该模型的元数据。它提供一些属性或方法来返回该模型的元数据信息。在模型上应用的数据注解(特性)也会被提取出来用于初始化元数据对象。而假如你想为模型增加一些自定义的元数据或修改已经应用在模型上的某些元数据,那么你可以考虑使用AdditionalMetadataAttribute或AllowHtmlAttribute特性,这两个特性都实现了IMetadataAware接口,IMetadataAware接口提供OnMetadataCreate方法,该方法要求接收一个ModelMetadata对象(模型的元数据)作为参数,这样,就可以在OnMetadataCreate方法中(创建ModelMetadata时)增加一些元数据或修改已经应用在模型上的某些元数据。

AdditionalMetadataAttribute特性

作用:此特性类实现了IMetadataAware接口以支持其他自定义的元数据。

  1. AdditionalMetadataAttribute; (string name | object value)
  2. name
  3. //自定义元数据的名称
  4. value
  5. //自定义元数据的值

AllowHtmlAttribute特性

作用:为了防止用户通过脚本注入攻击应用程序(XSS)所提供的一道验证开关。

  1. AllowHtmlAttribute;()
  2. //ASP.NET MVC默认会验证提交的数据是否包含Html,如果有则会把异常抛到客户端,如果应用了此特性则不会验证

ASP.NET MVC - 模型与元数据(进阶)的更多相关文章

  1. ASP.NET没有魔法——ASP.NET MVC 模型绑定解析(下篇)

    上一篇<ASP.NET没有魔法——ASP.NET MVC 模型绑定解析(上篇)>文章介绍了ASP.NET MVC模型绑定的相关组件和概念,本章将介绍Controller在执行时是如何通过这 ...

  2. [转] ASP.NET MVC 模型绑定的功能和问题

    摘要:本文将与你深入探究 ASP.NET MVC 模型绑定子系统的核心部分,展示模型绑定框架的每一层并提供扩展模型绑定逻辑以满足应用程序需求的各种方法. 同时,你还会看到一些经常被忽视的模型绑定技术, ...

  3. ASP.NET MVC模型绑定的6个建议(转载)

    ASP.NET MVC模型绑定的6个建议 发表于2011-08-03 10:25| 来源博客园| 31 条评论| 作者冠军 validationasp.netmvc.netasp 摘要:ASP.NET ...

  4. ASP.NET没有魔法——ASP.NET MVC 模型绑定

    在My Blog中已经有了文章管理功能,可以发布和修改文章,但是对于文章内容来说,这里缺少最重要的排版功能,如果没有排版的博客很大程度上是无法阅读的,由于文章是通过浏览器查看的,所以文章的排版其实与网 ...

  5. ASP.NET MVC - 模型验证

    ASP.NET MVC - 模型验证(Model verification) 模型验证原理浅析 模型验证用到了模型绑定器.模型验证器(System.Web.Mvc.DataAnnotationsMod ...

  6. asp.net mvc 模型验证组件——FluentValidation

    asp.net mvc 模型验证组件——FluentValidation 示例 using FluentValidation; public class CustomerValidator: Abst ...

  7. asp.net Mvc 模型绑定项目过多会导致页面运行时间卡

    asp.net Mvc 模型绑定项目过多会导致页面运行时间卡的问题. 解决方式就是采用ModelView方式进行精简,已减少模型绑定及验证的时间.

  8. 扩展 ASP.NET MVC 模型扩展 – ASP.NET MVC 4 系列

           大部分人不能将核心运行时(System.Web 中的类)和 ASP.NET Web Forms 应用程序平台(System.Web.UI 中的类)区分开来.        ASP.NET ...

  9. Asp.Net MVC 模型验证详解-实现客户端、服务端双重验证

    概要 在asp.net webform开发中经常会对用户提交输入的信息进行校验,一般为了安全起见大家都会在客户端进行Javascript(利于交互).服务端双重校验(安全).书写校验代码是一个繁琐的过 ...

随机推荐

  1. vertical-align垂直对齐用法

    一.垂直对齐方式{vertical-align:middle/top/bottom:} <img>垂直对齐方式:1)给自身加vertical-align:再设置line-height即可: ...

  2. 异常处理和Throwable中的几个方法

    package cn.lijun.demo; /* * try { //需要被检测的语句. } catch(异常类 变量) { //参数. //异常的处理语句. } finally { //一定会被执 ...

  3. 6.Django Admin学习

    ##创建超级用户 python manage.py createsuperuser 英文界面换成中文: 修改setting.py zh_Hans ##后台显示数据 django requets get ...

  4. python: 基本知识(二)

    1.set() set() 函数创建一个无序不重复元素集,可进行关系测试,删除重复数据,还可以计算交集.差集.并集等. x = set('hello’) y = set('world') x ---- ...

  5. angular cli全局版本大于本地版本 把本地版本升级方式

    查看 angular 版本  ng version 如出现提示 Your global Angular CLI version (xxx) is greater than your local ver ...

  6. 剑指Offer_编程题_3

    题目描述 输入一个链表,从尾到头打印链表每个节点的值. /** * struct ListNode { * int val; * struct ListNode *next; * ListNode(i ...

  7. jvm_tool jconsole/ jprofiler/ JProbe/ VirtualVm/ TPV/ YourKit/ ITCAM/ MAT/ MDD4J

    S 学习jvm,关于MAT an internal error occurred during:"Parsing heap dump" from问题 https://www.cnb ...

  8. Arduino、bootloader、BadUSB、及其相关硬件知识入门学习

    内容中包含 base64string 图片造成字符过多,拒绝显示

  9. css3 实现波浪(wave)效果

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. layui(九)——flow组件常见用法总结

    该模块包含 信息流加载 和  图片懒加载  两大核心支持,无论是对服务端.还是前端体验,都有非常大的性能帮助.下边分别给出了这两种技术的使用方法 一.信息流加载 信息流加载的核心方法时  flow.l ...