点击这里给我发消息 点击这里给我发消息

Asp.Net Mvc Beta新特性之自动绑定(2)-深入探索篇

添加时间:2010-1-5
    相关阅读: 项目
在上篇中介绍了自动绑定的基本用法,在本篇中,我们将深入了解自动绑定的工作原理.

  自动绑定的确是让人感到兴奋的特性,然而,为了让它可以在我们的项目中更好的工作,我们有必要深入了解如何更进一步细调该特性以及它是如何工作的.而本文正式即将揭开这个谜底.

  为了更好的了解该特性,我们有必要到codeplex去下载一份asp.net mvc的源代码并分析之,在本文写作的时候,codeplex上已经放上了beta版的源码,如果想进一步了解的朋友可以下载并对照本文分析.

  在beta版中,新增了自动绑定这一特性,并对绑定特性做了一定的修改

  新增BindAttribute:自动绑定特性设置

  修改DefaultModelBinder:自动绑定的实现部分

  修改ControllerActionInvoker:绑定的调用入口

  新增ModelBinderContext,封装绑定所需数据

  新增BinderResult,封装绑定结果

  其他不大重要的修改略过

  我们一步步来分析绑定的执行过程,首先肯定在ControllerActionInvoker中,看到GetParameterValue方法:

Asp.Net Mvc Beta新特性之自动绑定(2)-深入探索篇这儿便是对每个参数都尝试调用ModelBinder来绑定参数,这儿的GetModelBinder方法和P5的一样,在我们自定义ModelBinder的情况下可以进行自定义绑定,然而在自动绑定的时候获取的则是DefaultModelBinder,然后在GetPropertyFilter方法中通过查阅BindAttribute来获取关于绑定的设置.最后对数据进行绑定.

  关键的,我们需要对DefaultModelBinder进行分析,然而在此之前,还有一个类也是需要我们仔细看看的,那就是BindAttribute,该特性是用来修饰参数的,它有4个重要的属性:Include,Exclude,Prefix和一个方法:IsPropertyAllowed,分别用来设定:绑定的字段,不绑定的字段,参数前缀和判断给定的字段是否设定运行绑定,且该方法会作为一个Predicate<string>委托封入ModelBinderContext传入BindModel方法.

现在来讨论使用默认绑定的情况,首先给出DefaultModelBinder的所有方法:

Asp.Net Mvc Beta新特性之自动绑定(2)-深入探索篇

  分别简介下这些方法的作用:

  BindModel:对外的调用接口,根据传入的ModelBinderContext绑定值

  BindModelCore:绑定自定义类型,自定义类型数组或者自定义类型字典

  BindProperty:绑定某个指定的属性,(此处是一个递归调用,仍然调用DefaultModelBinder进行属性的绑定,也就是说,理论上DefaultModelBinder可以对任意深度的属性进行绑定)

  ConvertSimpleArrayType,ConvertSimpleType,用来做类型转换,一个转换数组一个转换普通类型

  CreateArray:创建一个数组对象

  CreateModel:创建一个普通对象

  CreateSubIndexName:创建子索引名,命名方式为prefix[indexName]

  CreateSubPropertyName:创建子属性名,命名方式为prefix.propertyName

  GetBinder:获取modelType的Binder对象

  GetElementType:获取一个类型的ElementType

  GetSimeType:对给定的ModelBinderContext进行简单值绑定(也就是调用该方法时假定获取的数据是简单类型)

  IsCollectionInserface:判断是否是数组类型

  IsDictinaryInterface:判断是否是字典类型

  IsSimpleType:是否是简单类型(在这儿判断是否是值类型或者string)

  TryUpdateSimpleCollection:尝试绑定一个简单数组(即绑定Collection或者Collection<T>,且T能通过IsSimpleType)

  UpdateCollection:绑定一个数组,该数组一般为Collection<T>,且T是自定义类型

UpdateDictionary:绑定一个字典类型

  通过以上方法的浏览,我们发现,DefaultModelBinder可以进行绑定的数据很多,包括简单类型(值类型和string).自定义类型,数组,字典,同时由于采用了递归调用,理论上可以绑定任意深度的数据,由于这儿绑定的调用比较复杂,且本人表达能力有限,本文将不再详细讲述绑定的工作流程,下面将总结下绑定的规则:

  默认绑定采用反射的方式将数据绑定到所需对象上

  绑定参数有可选特性BindAttribute定义

  BindAttribute中可以手动设置允许绑定的属性或者不允许绑定的属性,url取参前缀

  默认情况下所有属性都进行绑定

  DefaultModelBinder采用递归对所有需要绑定的参数进行绑定

  普通参数的命名方式为:prefix.protertyName,且默认情况下prefix为类型名.如对象MyData拥有类型为string的属性Name,那么在ValueProvider中取值的名称应该为mydata.name,命名不分大小写

  简单数组命名方式为prefix.protertyName,其中proertyName为数组名,可以存在多个

  对于自定义类型数组和字典,绑定必须提供如下参数:

  index-必须提供一个或多个,指示绑定的子元素名,可存在多个

  数组必须提供一个或者多个以protertyName[indexName].subProtertyName形式结尾的表单数据,其中protertyName为数组名,indexName为index中定义过的名称,subProteryName为自定义类型的属性名.

  字典必须提供一个或者多个protertyName[indexName].key和protertyName[indexName].value的表单数据,其中protertyName为字典名称,indexName为index中定义过的名称,key代表字典中的key绑定,value代表字典中的value绑定,如果key或者value为非简单类型,表单的定义继续参照前面

对于以上绑定,如果子级属性为复杂类型,可以依次按照此规则命名表单数据

  下面我们通过例子来分别描述上面的规则:

  在体验篇中,我们看到对article的表单命名为article.title,article.content等,这就是根据第6条,父类和属性用.来间隔,对简单数据的命名,article.tags,多个同名表单代表多个数族元素,参考第7条,在这儿,如果在article参数中显式定义了prefix,则需要对应对表单名进行修改.对于属性为自定义类型的,继续使用.间隔,比如上文中的article.advancearticle.today等,此处参考第7,9条,这些部分的例子可以参考第一篇,本篇中将不再说明.

  本篇中将重点介绍自定义类型数组,字典以及多级属性绑定,下面展示如何绑定一个ICollection<T>,T为自定义类型,比如在AdvanceArticle中添加一个属性Reads,这是一个自定义类型,包含Name和Source,实例代码如下;

Asp.Net Mvc Beta新特性之自动绑定(2)-深入探索篇

  然后根据规则在表单aspx中加入:

Asp.Net Mvc Beta新特性之自动绑定(2)-深入探索篇

  这儿给这个数组传入了两个元素,分别对应article.reads.index中的0和aa,下面的article.reads[0].name和article.reads[0].source表示第一个元素的子属性,依次类推.如果您在应用中需要在数组中添加更多元素,可以采用js动态添加表单域的方法,不过每次添加必须对应添加index和对应的子属性表单.

  然后是绑定Dictinary<TKey,TValue>,我们在AdvanceArticle中继续加入新属性

Asp.Net Mvc Beta新特性之自动绑定(2)-深入探索篇

  然后在aspx中加入表单:

Asp.Net Mvc Beta新特性之自动绑定(2)-深入探索篇

  和数组类似的,需要定义article.source.index,此处也显式定义了两个字典元素,分别是user和vip(注意,这儿的user和vip并不代表字典key,字典key是需要从表单绑定的),然后分别定义article.source[user].key和article.source[user].key等.如果有更多的元素,也需要按照此规则加入.

  同样的,这儿的key和value也不局限于简单类型,如果key和value是自定义类型,则可以按照前面的规则继续向下定义.

  最后需要说明几点: By Leven

  2008-10-22

  1.   绑定取值不限于表单域,在Beta中加入了ValueProvider,只要是能在ValueProvider中能取到的值都能绑定.

  2.   自动绑定是基于反射,如果你嫌效率不够高,请采用自定义ModelBinder的方式对特定的类型进行特定的绑定已提升效率

  3.   自动绑是单向的,如果想实现在route中能接受该参数,可以采用重写绑定对象的ToString方法输出对应QueryString的方式,也就是说,如果想在调用Url.Action(“xxx”,new { article= myArticle })能正确传入传出参数,可以重写Article的ToString方法,在提供一个类似article.title=xxx&article.content=xxx的字符串格式提供一个帮助类,将将数据分别放入ValueProvider,而调用Url方法时采用类似Url.Action(“xxx”,article.ToRouteValue())的方法

本文作者:
咨询热线:020-85648757 85648755 85648616 0755-27912581 客服:020-85648756 0755-27912581 业务传真:020-32579052
广州市网景网络科技有限公司 Copyright◎2003-2008 Veelink.com. All Rights Reserved.
广州商务地址:广东省广州市黄埔大道中203号(海景园区)海景花园C栋501室
= 深圳商务地址:深圳市宝源路华丰宝源大厦606
研发中心:广东广州市天河软件园海景园区 粤ICP备05103322号 工商注册