ASP.NET MVC Model元数据(四)
ASP.NET MVC Model元数据(四)
前言
前面的篇幅讲解了Model元数据生成的过程,并没有对Model元数据生成过程的内部和Model元数据结构的详细解释。看完本篇后将会对Model元数据有更清楚的了解,当然了也不会是特别全面的,因为后面还有篇幅。希望能给大家带来好的效果。
Model元数据
- 什么是Model元数据?
- 生成Model元数据的过程【一】
- 生成Model元数据的过程【二】
- ModelMetaData的定义、详解
- Model元数据应用(常用特性应用)-1
- Model元数据应用(自定义视图模板)-2
- Model元数据应用(IMetadataAware接口使用)-3
ModelMetaData的定义、详解
对于Model元数据的生成可否我们自己来定义呢?回答是肯定的,必须可以阿。MVC框架给我们提供了顶层基类,在调用的时候是从当前上下文中获取到系统默认实现类(或者是我们自定义的实现类)。我们来看一下示例代码1-1.
代码1-1
public class MyCustomModelMetadataProvider:DataAnnotationsModelMetadataProvider
{
protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
{
DataAnnotationsModelMetadata result = new DataAnnotationsModelMetadata(this, containerType, modelAccessor, modelType, propertyName, displayColumnAttribute); return result;
}
}
代码1-1中的MyCustomModelMetadataProvider类型继承自DataAnnotationsModelMetadataProvider类型,并且重写了CreateMetadata()的方法,在CreateMetadata()方法中会根据参数attributes中的特性信息来对Model元数据各种属性来操作赋值。这个会在下面说到,代码1-1中并没有对attributes参数这些来进行解析,而只是实例化了一个Model元数据类型(DataAnnotationsModelMetadata继承自ModelMetadata)用来返回。这样定义好了过后系统并不会调用我们自定义的实现,而是需要在项目启动的时候就添加到系统上下文中,我们就在Global.asax文件中的MvcApplication类型里的Application_Start()方法中来添加示例代码1-2.
代码1-2
ModelMetadataProviders.Current = new MyCustomModelMetadataProvider();
这样定义过后,系统框架在执行的时候就会调用我们的自定义实现了,还可以使用前面篇幅的示例来直接运行,什么结果我没试过不过肯定是不会有什么特殊效果,真正的目的不在这,而是在CreateMetadata()方法的入口处设上断点(图1)然后我们再次按F5执行程序,程序又会执行到我们自定义实现的CreateMetadata()方法。
图1
按照上面做的意义何在呢?这样做的意义在于在每次断点进来的时候,我们可以打开调试的即时窗口,并且输入CreateMetadata()方法参数的modelType来查看当前所要生成的Model元数据对应的类型或者是属性,也便于我们自己去更深入的学习。还有一个意思就是证明了我上篇所说的那样生成的过程。
下面我们来看一下系统默认提供的DataAnnotationsModelMetadataProvider类型中是怎么对Model元数据进行操作的,先看一下默认的实现代码,
代码1-3
protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
{
List<Attribute> attributeList = new List<Attribute>(attributes);
DisplayColumnAttribute displayColumnAttribute = attributeList.OfType<DisplayColumnAttribute>().FirstOrDefault();
DataAnnotationsModelMetadata result = new DataAnnotationsModelMetadata(this, containerType, modelAccessor, modelType, propertyName, displayColumnAttribute); // Do [HiddenInput] before [UIHint], so you can override the template hint
HiddenInputAttribute hiddenInputAttribute = attributeList.OfType<HiddenInputAttribute>().FirstOrDefault();
if (hiddenInputAttribute != null)
{
result.TemplateHint = "HiddenInput";
result.HideSurroundingHtml = !hiddenInputAttribute.DisplayValue;
} // We prefer [UIHint("...", PresentationLayer = "MVC")] but will fall back to [UIHint("...")]
IEnumerable<UIHintAttribute> uiHintAttributes = attributeList.OfType<UIHintAttribute>();
UIHintAttribute uiHintAttribute = uiHintAttributes.FirstOrDefault(a => String.Equals(a.PresentationLayer, "MVC", StringComparison.OrdinalIgnoreCase))
?? uiHintAttributes.FirstOrDefault(a => String.IsNullOrEmpty(a.PresentationLayer));
if (uiHintAttribute != null)
{
result.TemplateHint = uiHintAttribute.UIHint;
} EditableAttribute editable = attributes.OfType<EditableAttribute>().FirstOrDefault();
if (editable != null)
{
result.IsReadOnly = !editable.AllowEdit;
}
else
{
ReadOnlyAttribute readOnlyAttribute = attributeList.OfType<ReadOnlyAttribute>().FirstOrDefault();
if (readOnlyAttribute != null)
{
result.IsReadOnly = readOnlyAttribute.IsReadOnly;
}
} DataTypeAttribute dataTypeAttribute = attributeList.OfType<DataTypeAttribute>().FirstOrDefault();
DisplayFormatAttribute displayFormatAttribute = attributeList.OfType<DisplayFormatAttribute>().FirstOrDefault();
// SetFromDataTypeAndDisplayAttributes(result, dataTypeAttribute, displayFormatAttribute); ScaffoldColumnAttribute scaffoldColumnAttribute = attributeList.OfType<ScaffoldColumnAttribute>().FirstOrDefault();
if (scaffoldColumnAttribute != null)
{
result.ShowForDisplay = result.ShowForEdit = scaffoldColumnAttribute.Scaffold;
} DisplayAttribute display = attributes.OfType<DisplayAttribute>().FirstOrDefault();
string name = null;
if (display != null)
{
result.Description = display.GetDescription();
result.ShortDisplayName = display.GetShortName();
result.Watermark = display.GetPrompt();
result.Order = display.GetOrder() ?? ModelMetadata.DefaultOrder; name = display.GetName();
} if (name != null)
{
result.DisplayName = name;
}
else
{
DisplayNameAttribute displayNameAttribute = attributeList.OfType<DisplayNameAttribute>().FirstOrDefault();
if (displayNameAttribute != null)
{
result.DisplayName = displayNameAttribute.DisplayName;
}
} RequiredAttribute requiredAttribute = attributeList.OfType<RequiredAttribute>().FirstOrDefault();
if (requiredAttribute != null)
{
result.IsRequired = true;
} return result;
}
在代码1-3中,我们看到首先会根据参数attributes转换为Attribute集合类型的attributeList变量,然后就是在此集合中搜寻第一个DisplayColumnAttribute类型的特性,暂且先不说这个特性类型是干什么的,因为我现在也不太明白。
然后就是根据CreateMetadata()方法中的参数实例化一个DataAnnotationsModelMetadata类型的元数据,这个类型上面说过了。继续往下看,然后就到了从attributeList变量获取第一个HiddenInputAttribute类型的特性实例,在判断不为空后,对Model元数据DataAnnotationsModelMetadata类型变量result的两个属性开始赋值(下文中对Model元数据DataAnnotationsModelMetadata类型变量result统称叫result),首先第一个是Model元数据的TemplateHint属性,这个属性表示着这个Model元数据所表示的对象要使用哪个视图模板来生成Html代码(视图模板的内容这个系列的后面篇幅会有讲解,到时候再回头来看一下,学习嘛感觉就是一个迭代的过程)。然后是HideSurroundingHtml属性的赋值,对应的是HiddenInputAttribute类型的DisplayValue值,HiddenInputAttribute类型表示的是是否将属性或者字段值显示为隐藏的Input元素,如果我们这样写的话[HiddenInput(DisplayValue = false)],HideSurroundingHtml属性值则为true,代表的意思就是使用关联的Html元素来呈现对象模型,意思就是用HiddenInputAttribute类型所关联隐藏输入域来呈现我们所指定的属性或者字段。这里可能有点绕,不过不妨碍,下个篇幅会讲示例用的效果。
切回主题继续讲,下面则是从attributeList中获取UIHintAttribute类型的集合,并且经过一番判断获取一个UIHintAttribute类型的实例,并且还是赋值到TemplateHint属性(上面说过),这里就覆盖掉了,在我们使用默认的Model元数据提供程序的时候就要注意这些了,再继续往下看。
从attributeList中获取第一个EditableAttribute类型的实例,并且根据EditableAttribute类型实例中的AllowEdit属性值来设置result的IsReadOnly属性值,代表着指示这个模型是否只读,EditableAttribute类型指示模型是否可编辑的意思和下面的ReadOnlyAttribute类型很像,只不过同样是实现只读效果两个类型使用中设置的属性值是相反的。
同样是从attributeList获取符合类型条件的第一个DataTypeAttribute类型实例,还有个是DisplayFormatAttribute类型实例,这里会调用默认的提供程序里的另一个函数,在此就不做多的介绍了,我就稍微的说一下就行了。为什么把这两个放一起呢?因为他们都是对指定的模型输出格式的设置有关。
ScaffoldColumnAttribute类型实例表示着是否使用基架(模板视图辅助器的一种,EditorForModel属于其中之一),当某项属性上使用了这个特性类的时候,在使用基架的时候会直接跳过这项属性,在生成的页面中也不会发现这项属性。(遭到了嫌弃)
同样的DisplayAttribute类型的实例也是从attributeList获取符合类型条件的第一个,DisplayAttribute类型实例里有个Name属性会被设置到result的DisplayName属性,这个属性的意思就是指定的模型显示到页面的值。而DisplayNameAttribute类型实例的意思和DisplayAttribute类型的相近,只不过DisplayNameAttribute类型可以用于类类型,转定义我们一看便知。
最后对于RequiredAttribute类型实例的意思会在Model验证篇幅中说明。
作者:金源
出处:http://www.cnblogs.com/jin-yuan/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面
ASP.NET MVC Model元数据(四)的更多相关文章
- ASP.NET MVC Model验证(四)
ASP.NET MVC Model验证(四) 前言 本篇主要讲解ModelValidatorProvider 和ModelValidator两种类型的自定义实现,前者是Model验证提供程序,而Mod ...
- ASP.NET MVC Model绑定(四)
ASP.NET MVC Model绑定(四) 前言 前面的篇幅对于Model绑定器IModelBinder以及实现类型.Model绑定器提供程序都作了粗略的讲解,可以把Model绑定器想象成一个大的容 ...
- ASP.NET MVC Model元数据(五)
ASP.NET MVC Model元数据(五) 前言 在上一篇中我们描述了应用于Model上面的各种用于显示控制的特性类,在本篇中将详细的介绍这些特性类的应用,虽然它们跟Model元数据的直接关系并不 ...
- ASP.NET MVC Model元数据(三)
ASP.NET MVC Model元数据(三) 前言 在上篇中我们大概的讲解了Model元数据的生成过程,并没有对Model元数据本身和详细的生成过程有所描述,本篇将会对详细的生成过程进行讲解,并且会 ...
- ASP.NET MVC Model元数据(二)
ASP.NET MVC Model元数据(二) 前言 在上篇中,给大家留个对Model元数据的印象,并没有对Model元数据有过多的讲解,而在本篇中也不会对Model元数据的本身来解释,而是针对于它的 ...
- ASP.NET MVC Model元数据(一)
ASP.NET MVC Model元数据(一) 前言 在我初学的时候对Model元数据的概念很模糊,或者说是在大脑中没有它的一个模型,作为小白的我去看网上的一些文章还是两眼一黑啥都看不明白,然后我想退 ...
- ASP.NET MVC Model元数据
ASP.NET MVC Model元数据(三) 前言 在上篇中我们大概的讲解了Model元数据的生成过程,并没有对Model元数据本身和详细的生成过程有所描述,本篇将会对详细的生成过程进行讲解,并且会 ...
- 【笔记】ASP.NET MVC Model元数据
问题1:什么叫Model元数据? Model元数据,是针对数据类型的一种描述信息.由于复杂类型(或者说类型嵌套的存在,比如CustomerModel中有一个属性为复杂类型Address)的存在,因此M ...
- ASP.NET MVC Model绑定(一)
ASP.NET MVC Model绑定(一) 前言 ModelMetadata系列的结束了,从本篇开始就进入Model绑定部分了,这个系列阅读过后你会对Model绑定有个比较清楚的了解, 本篇对于Mo ...
随机推荐
- 从源码看Azkaban作业流下发过程
上一篇零散地罗列了看源码时记录的一些类的信息,这篇完整介绍一个作业流在Azkaban中的执行过程,希望可以帮助刚刚接手Azkaban相关工作的开发.测试. 一.Azkaban简介 Azkaban作为开 ...
- 通过AngularJS实现前端与后台的数据对接(二)——服务(service,$http)篇
什么是服务? 服务提供了一种能在应用的整个生命周期内保持数据的方法,它能够在控制器之间进行通信,并且能保证数据的一致性. 服务是一个单例对象,在每个应用中只会被实例化一次(被$injector实例化) ...
- webpack的使用
1.webpack是什么? 打包前端项目的工具(为项目提高逼格的东西). 2.webpack的基本命令 webpack#最基本的启动webpack命令 webpack-w #提供watch方法,实时进 ...
- python 入门笔记
1.pip包安装 pip install *** pip 中http和https代理设置(/etc/profile) 2.强制保存 :w !sudo tee % 3.cffi是python调用C的包 ...
- redis成长之路——(二)
redis操作封装 针对这些常用结构,StackExchange.Redis已经做了一些封装,不过在实际应用场景中还必须添加一些功能,例如重试等 所以对一些常功能做了一些自行封装SERedisOper ...
- BPM体系文件管理解决方案分享
一.方案概述 企业管理在很大程度上是通过文件化的形式表现出来,体系文件管理是管理体系存在的基础和证据,是规范企业管理活动和全体人员行为,达到管理目标的管理依据.对与公司质量.环境.职业健康安全等体系有 ...
- 【干货分享】流程DEMO-借款申请
流程名: 借款申请 业务描述: 当员工个人在工作中需要进行借款时,通过此项流程提交借款申请,审批通过后,财务部进行款项支付. 流程相关文件: 流程包.xml WebService业务服务.xm ...
- 【干货分享】流程DEMO-固定资产转移流程
流程名: 固定资产转移 业务描述: 固定资产从某员工转移至另一员工,转出人与转入人必须不同 流程相关文件: 流程包.xml 流程说明: 直接导入流程包文件,即可使用本流程 表单: 流程: ...
- Ajax.BeginForm方法 参数
感谢博主 http://www.cnblogs.com/zzgblog/p/5454019.html toyoung 在Asp.Net的MVC中的语法,在Razor页面中使用,替代JQuery的Aja ...
- mysql 5.7中的用户权限分配相关解读!
这篇文章主要介绍了MySQL中基本的用户和权限管理方法,包括各个权限所能操作的事务以及操作权限的一些常用命令语句,是MySQL入门学习中的基础知识,需要的朋友可以参考下 一.简介 各大帖子及文章都会讲 ...