模型元数据ModelMetaData是MVC中很重要的概念,它包括但不仅限于 模型的类型,模型包含了哪些属性,属性都是什么类型的,属性上都有什么特性。
ASP.NET MVC3.0 提供了默认的模型元数据 DataAnnotationsModelMetadata 继承自ModelMetadata(另外系统提供了默认的模型元数据提供器DataAnnotationsModelMetadataProvider)
public class DataAnnotationsModelMetadata : ModelMetadata
它的构造函数如下
public DataAnnotationsModelMetadata(DataAnnotationsModelMetadataProvider provider, Type containerType, Func modelAccessor, Type modelType, string propertyName, DisplayColumnAttribute displayColumnAttribute);
DataAnnotationsModelMetadata类有常用的几个属性
DisplayName 显示名称,DisplayFormatString格式字符串
TemplateHint 获取一个值选择使用哪个模版
对于DisplayName ,LabelFor<TModel, TValue> 方法中使用此属性来生成标签文本. 意思就是一旦我们的model上有定义了DispalyName特性,那么view中使用html.editForModel()方法就会自动为model的这个属性显示出label标签" <label for="username">名称</label></
[Display( Name="名称",Order=2)] //order属性改变在html页面中的排列顺序
public string username { get; set; }
html源代码:
<div class="editor-label"><label for="username">名称</label></div>
<div class="editor-field"><input class="text-box single-line" data-val="true" data-val-maxwords="名称 has too many words" data-val-maxwords-wordcount="2" data-val-required="名称 字段是必需的。" id="username" name="username" type="text" value=""> <span class="field-validation-valid" data-valmsg-for="username" data-valmsg-replace="true"></span></div>
属性username上用的Display特性就是System.ComponentModel.DataAnnotations.DisplayAttribute类提供一个通用特性,使您可以为实体分部类的类型和成员指定可本地化的字符串
另外还有一些特性来自System.Web.MVC 和 System.ComponentModel.DataAnnotations,名称凡类似 XXXXAttribute的都为特性类,都有特定的使用范围,有的限制模型属性,有的限制Contrller,有的限制Action等等。
下面列举了这2个命名空间下,内置的而且常用的特性类
1)System.Web.MVC空间下的
AcceptVerbsAttribute,ActionFilterAttribute,ActionNameAttribute,AsyncTimeoutAttribute,AuthorizeAttribute,BindAttribute,
ActionFilterAttribute 表示所有操作-筛选器特性的基类
HttpDeleteAttribute 类,表示一个特性,该特性用于限制操作方法,以便该方法仅处理 HTTP DELETE 请求
HttpGetAttribute,HttpPostAttribute 表示特性,用于限制操作方法,仅限处理PUT请求
HttpPutAttribute 表示一个特性,该特性用于限制操作方法,以便该方法仅处理 HTTP PUT 请求。
例:ActionNameAttribute 指定action的实际actionname,用法如下
[ActionName()]
public ActionResult Index()
例:HiddenInputAttribute类,表示一个特性,该特性用于指示是否应将属性值或字段值呈现为隐藏 input 元素
[AttributeUsageAttribute(AttributeTargets.Class|AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class HiddenInputAttribute : Attribute
[HiddenInput]
public string zhanshi { get; set; } //只隐藏了Input,但是label还是显示了zhanshi
[HiddenInput(DisplayValue=false)] //只生了 input hidden zhanshi2 没显示
public string zhanshi2 { get; set; }
当DisplayValue设置为false时候,只为zhangshi2属性生成了一个 <input type=”hidden” name=”zhangshi2” value>元素。但是zhangshi生成了2个元素,一个displayName元素,照常显示,而input元素则隐藏了。
2)System.ComponentModel.DataAnnotations 空间下的特性类
AssociationAttribute 指定某个实体成员表示某种数据关系,如外键关系。
DataTypeAttribute 指定要与数据字段关联的附加类型的名称。 为属性呈现html时候才有用,数据验证的时候不使用这个,你懂的。
DisplayColumnAttribute 将所引用的表中显示的列指定为外键列。
DisplayFormatAttribute 指定 ASP.NET 动态数据如何显示数据字段以及如何设置数据字段的格式。
EditableAttribute 指示数据字段是否可编辑。
EnumDataTypeAttribute 使 .NET Framework 枚举能够映射到数据列。
FilterUIHintAttribute 表示一个特性,该特性用于指定列的筛选行为。
KeyAttribute 表示一个或多个用于唯一标识实体的属性。
MetadataTypeAttribute 指定要与数据模型类关联的元数据类。
RangeAttribute 指定数据字段值的数值范围约束。
RegularExpressionAttribute 指定 ASP.NET 动态数据中的数据字段值必须与指定的正则表达式匹配。
RequiredAttribute 指定需要数据字段值。
ScaffoldColumnAttribute 指定类或数据列是否使用基架。
ScaffoldTableAttribute 指定类或数据表是否使用基架。
StringLengthAttribute 指定数据字段中允许的最小和最大字符长度。
TimestampAttribute 将列的数据类型指定为行版本。
UIHintAttribute 指定动态数据用来显示数据字段的模板或用户控件。
ValidationAttribute 作为所有验证特性的基类。
下面例子针对DataTypeAttribute进行应用
[DataType(DataType.EmailAddress)] //表是货币值
[Display(Order=1)] //html显示的顺序
public string lastname { get; set; }
view:@Html.DisplayForModel()
呈现出的html代码和外观: 点击邮箱名称就可以直接调用默认操作系统的邮件系统。
<div class="display-field"><a href="mailto:sdfsd@sina.com">sdfsd@sina.com</a></div>,即使model中lastname设置成不正确的email格式,也会展现出。
html代码:<a href="mailto:sdfsd">sdfsd</a>
Date 表示日期值。
Time 表示时间值。
Duration 表示对象存在的一段连续时间。
PhoneNumber 表示电话号码值。
Currency 表示货币值。
Text 表示所显示的文本。
Html 表示一个 HTML 文件。
MultilineText 表示多行文本。
EmailAddress 表示电子邮件地址。
Password 表示密码值。
Url 表示 URL 值。
ImageUrl 表示图像的 URL。
注意DataType不能重复对同一个属性使用
例子:
[DataType(DataType.DateTime)] //表是货币值
[Display(Order=1)]
public string lastname { get; set; }
lastname设置为 DateTime.Now.ToLongDateString() =2014年4月1日
如何lastname能转换为DateTime就转换,不能转换就按照原来的显示。
上面就是常用的特性,有些特性是用来辅助将属性或者元素呈现出来,有些还带有验证功能。
自定义模版,比如自定义控件,当某个属性拥有了[UIHint("模版名称")]特性,那么就会按照新的方式展示,不会按照默认的方式执行。
例:model:public string name{get;set;}
view:@html.DisplayforModel()
最终为属性name呈现的html元素为input输入框,这个input输入框就是默认的模版,当知道是string或者Int类型后,再没设置其他模版的前提下,选择默认的input元素。
如果我不想让对string类型,在呈现的时候显示input输入框元素,那么我们可以自定义模版,然后在属性上应用[UIHint(自定义的新模版)]就可以不使用默认的input元素了。
现在开始动手,假设将string类型的属性呈现出另外的效果,比如display时候显示 2个输入,编辑时候显示2个输入框。
先新建2个文件夹,注意文件夹名称必须是分别为DisplayTemplates,EditorTemplates
然后在文件夹里建立2个相同名称的view视图 Data.cshtml。Data就是新定义的模版名称。
代码分别如下
DisplayTemplates/Data.cshtml
<script type="text/javascript">$(function () {$(".datepicker").datepicker({ "dateFormat": "yy-mm-dd" })});</script>@Html.TextBox("", String.Format("{0:yyyy-MM-dd}", ViewData.TemplateInfo.FormattedModelValue), new { @class = "datepicker" })
EditTemplates/Data.cshtml
@Html.DropDownList("",MvcApplication1.Sample_ModelMeta.DropDownListMenu.年齡選項(),"请选择年龄")
model中设置模版
public class user{[UIHint("Data")]public string lastname { get; set; }}
view: 第一个是编辑,第2个是展示
@Html.DisplayFor(model=>model.lastname,"Data")@Html.EditorFor(model=>model.lastname,"Data")
action中设置lastname=DateTime.Now
html代码:
<div>显示:<input id="lastname" name="lastname" type="text" value="2014/4/2"><script type="text/javascript">$(function () {$(".datepicker").datepicker({ "dateFormat": "yy-mm-dd" })});</script>编辑:<input class="datepicker hasDatepicker" id="lastname" name="lastname" type="text" value="2014/4/2"></div>
效果图: 使用EditorFor呈现的是一个输入框,当你点击后可以选择时间。这个时间控件是Jquery Ui中的,所以view要引用jquery.ui.cs
MVC查找模版的路径先为当前controller同名的view文件夹下查找,找不到了,再最后是shared文件夹中查找,如果没找到任何模版,则还是按照默认显示)
元数据定制,就是在属性上添加自定义特性,可以设置元数据。 例如 自定义[displayText]特性
至于如何自定义,首先我们要查看系统默认存在的一些特性的类的结构
public class DisplayTextAttribute:Attribute,IMetadataAware
继承Attribute类和IMetadataAware接口,实现接口中的OnMetadatAware接口
public void OnMetadataCreated(ModelMetadata metadata){this.DisplayName=this.DisplayName??(metadata.PropertyName??metadata.ModelType.Name);if(null==this.ResourceType){metadata.DisplayName=this.DisplayName;return ;}PropertyInfo property=this.ResourceType.GetProperty(this.DisplayName, BindingFlags.NonPublic|BindingFlags.Public| BindingFlags.Static);//PropertyInfo property = metadata.ModelType.GetProperty(this.DisplayName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);metadata.DisplayName = "我把所有列名都改了";//property.GetValue(null, null).ToString();metadata.TemplateHint="MultilineText";}
在方法中,我们可以设置模型元数据的信息 ,比如此处我将DisplayName都设置成了“xxx”,并设置了模版 为MultilineText。
[DisplayText]public string Name { get; set; }
效果展示:@html.displayForModel() 为Name呈现一个 label内容为“我把所有列名都改了”,而且输入框显示的是多行模式。
元数据提供系统,ASP.net提供了一个可插拔的模型元数据提供系统DataAnAnnotationModelMetaProvder,可插拔的意思就是可以自定义然后替换掉默认的元数据提供系统。
若要自定义,请继承ModelMetadataProvider类,实现3个方法。
下面是部分自定义元数据提供系统CustomerMetaProvider类
namespace MvcApplication1.CustomerMetaProvider{public class CustomerMetadataProvider : ModelMetadataProvider{public override IEnumerable<ModelMetadata> GetMetadataForProperties(object container, Type containerType){throw new NotImplementedException();}public override ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, Type containerType, string propertyName){throw new NotImplementedException();}public override ModelMetadata GetMetadataForType(Func<object> modelAccessor, Type modelType){throw new NotImplementedException();}}public class Contact{public string FirstName { get; set; }public string LastName { get; set; }public string EmailAddress { get; set; }}}
应用上面的提供系统,要在Global.asax.cs 的Application_Start中加上一句 ModelMetadataProviders.Current = new CustomModelMetadataProviderWithConfig();
这样就要MVC项目中当模型绑定和为属性呈现元素时候都要从上面自定义的元数据提供系统提供ModelMetaData,所以上面的3个方法一定要重写。
本例子没实现这3个方法,待补充!
至此,模型元数据的意义,模型元数据定制,自定义模型元数据提供系统,以及自定义html模版 都研究完成。
再加上签名的 模型绑定器,自定义验证特性,自定义验证特性的客户端验证都已完成。
目前还剩下 自定义值提供器 和 自定义视图模版和视图结构。