欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

ASP.NET MVC Model元数据(四)

程序员文章站 2022-03-23 08:07:45
前言   前面的篇幅讲解了model元数据生成的过程,并没有对model元数据生成过程的内部和model元数据结构的详细解释。看完本篇后将会对model元数据有更清楚...
前言

 

前面的篇幅讲解了model元数据生成的过程,并没有对model元数据生成过程的内部和model元数据结构的详细解释。看完本篇后将会对model元数据有更清楚的了解,当然了也不会是特别全面的,因为后面还有篇幅。希望能给大家带来好的效果。

 

 

 

 

 

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文件中的mapplication类型里的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验证篇幅中说明。