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

1
2
3
4
5
6
7
8
9
  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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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验证篇幅中说明。



     本文转自jinyuan0829 51CTO博客,原文链接:http://blog.51cto.com/jinyuan/1430532,如需转载请自行联系原作者

相关文章
|
3月前
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
38 0
|
28天前
|
开发框架 前端开发 .NET
进入ASP .net mvc的世界
进入ASP .net mvc的世界
27 0
|
1月前
|
开发框架 前端开发 .NET
C# .NET面试系列六:ASP.NET MVC
<h2>ASP.NET MVC #### 1. MVC 中的 TempData\ViewBag\ViewData 区别? 在ASP.NET MVC中,TempData、ViewBag 和 ViewData 都是用于在控制器和视图之间传递数据的机制,但它们有一些区别。 <b>TempData:</b> 1、生命周期 ```c# TempData 的生命周期是短暂的,数据只在当前请求和下一次请求之间有效。一旦数据被读取,它就会被标记为已读,下一次请求时就会被清除。 ``` 2、用途 ```c# 主要用于在两个动作之间传递数据,例如在一个动作中设置 TempData,然后在重定向到另
95 5
|
5月前
|
开发框架 自然语言处理 前端开发
基于ASP.NET MVC开发的、开源的个人博客系统
基于ASP.NET MVC开发的、开源的个人博客系统
51 0
|
8月前
|
SQL 开发框架 前端开发
[回馈]ASP.NET Core MVC开发实战之商城系统(完:内附源码)
经过一段时间的准备,【ASP.NET Core MVC开发实战之商城系统】已经完成,目前代码已开发完成,先将全部内容整理分享,如有不足之处,还请指正。
106 0
|
8月前
|
开发框架 前端开发 .NET
[回馈]ASP.NET Core MVC开发实战之商城系统(六)
经过一段时间的准备,新的一期【ASP.NET Core MVC开发实战之商城系统】已经开始,在之前的文章中,讲解了商城系统的整体功能设计,页面布局设计,环境搭建,系统配置,及首页【商品类型,banner条,友情链接,降价促销,新品爆款】,商品列表页面,商品详情,购物车等功能的开发,今天继续讲解订单管理功能开发,仅供学习分享使用,如有不足之处,还请指正。
214 0
|
前端开发 .NET 数据安全/隐私保护
|
前端开发 .NET 开发框架
|
Web App开发 前端开发 数据安全/隐私保护