(三)关于DataService的讨论
在写本文时,我细致地使用关键字“DataService”搜索了整个因特网但却得到极少的几篇与这个主题相关的文章(例如这一篇http://forums.asp.net)。所以,我们的主要参考资料就是随同MS AJAX框架发行的几个例子。此外,我还使用VS2005中的对象浏览器和反射工具搜索到了有关的一少部分信息。现在,我把它们粘合在一起,谈谈自己对这个“神秘”的DataService的理解。
首先,尽管最近你可以从WEB或者是MS AJAX所附教程中非常容易地找到大量的从ASP.NET AJAX框架的客户端JavaScript中消费普通WEB服务相关的操作技巧,但是有关于直接从客户端JavaScript消费派生自DataService的WEB服务方面的内容却实在不多。根据本人的粗浅研究,DataService应该主要使用于如下的典型场所下:当我们使用高级客户端控件ItemView,ListView,而且其数据源来自于WEB服务提供的数据库,并且要求进行数据库相关的典型操作时(例如CRUD);而在其它情况下,我们一般选用普通的WebService。微软是否针对ListView/ItemView特别设计了DataService?通过进一步使用.NET对象浏览器和Lutz Roeder的高级.NET Reflector工具(提示:这是一个相当优秀的工具,借助于它你可以获取类DataService的全部源码)剖析程序集—Microsoft.Web.Preview.dll,我们还注意到DataService派生自WebService,而且只对外暴露了两个Web方法:
列表4
|
public DataTable GetData(object parameters, string loadMethod); public DataTable SaveData(ChangeList changeList, object parameters,string loadMethod); |
通过进一步分析位于文件PreviewScript.js内的Sys.Preview.Data.DataSource.save和Sys.Preview.Data.DataSource.load的源码,我们会很容易发现:
1、方法save要求DataSource的serviceType属性必须为类型Sys.Preview.Data.ServiceType.DataService;之后,方法save被转向调用类DataService的方法SaveData;
2、对于方法load则存在两种情况:当DataSource的serviceType属性为类型DataService时,方法load被转向调用类DataService的方法GetData;而当DataSource的属性serviceType不属于类型DataService时(例如为Handler),系统将创建一个普通的代理,然后把方法load转发到Sys.Net.WebRequest()。当我们使用.NET Reflector来进一步研究类DataService的方法SaveData和GetData时,我们发现了更为有趣的事情—了解DataSource的loadMethod属性的意义以及数据库CRUD操作如何响应于你的DataService的Delete(DeleteRecords),Insert(InsertRecords),Select(SelectRecords)和Update(UpdateRecords)方法的,还蕴含了更多的秘密……
【作者注】极力推荐你研究一下类DataService的实现源码,你将会发现许多有用的东西。
借助于新引入的属性—DataObjectMethod和DataObjectField(你可以参考MSDN中两个类DataObjectFieldAttribute和DataObjectMethodAttribute作进一步研究),我们可以很容易地实现我们的目标—提供为控件DataSource所使用的属性和方法(如Fill,Select,Update,Insert和Delete等操作)。所有这些都可以在下一节中通过轻松的xml-script声明式编程来实现。
(四)实现绑定
现在,我们来看一下如何使用xml-script声明性方式来实现对于控件ListView的数据绑定。下面是相应于前面HTML元素定义部分的xml-script代码部分。
列表5
广州网站建设,网站建设,广州网页设计,广州网站设计
|
<script type="text/xml-script"> <page xmlns="http://schemas.microsoft.com/xml-script/2005"> <components> <dataSource id="EmployeeDataSource" serviceURL="EmployeeDataService.asmx" > </dataSource> <listView id="searchResults" itemTemplateParentElementId="searchResults_layoutTemplate" > <bindings> <binding dataContext="EmployeeDataSource" dataPath="data" property="data" /> </bindings> <layoutTemplate> <template layoutElement="searchResults_layoutTemplate" /> </layoutTemplate> <itemTemplate> <template layoutElement="searchResults_itemTemplate"> <label id="searchResults_ID"> <bindings> <binding dataPath="Id" transform="Add" property="text" /> </bindings> </label> <label id="searchResults_Name"> <bindings> <binding dataPath="Name" property="text" /> </bindings> </label> <label id="searchResults_Address"> <bindings> <binding dataPath="Address" property="text" /> </bindings> </label> </template> </itemTemplate> <separatorTemplate> <template layoutElement="searchResults_separatorTemplate" /> </separatorTemplate> <emptyTemplate> <template layoutElement="NoDataTemplate" /> </emptyTemplate> </listView> <application> <load> <invokeMethodAction target="EmployeeDataSource" method="load" /> </load> </application> </components> </page> </script> |
在上面代码的第一行,我们定义了一个将用于后面相应控件的dataSource。注意,在此虽然没有显式声明,但是dataSource控件的ServiceType属性已经被置为DataService。接下来,我们开始具体的数据绑定,使用属性dataContext指定控件ListView的数据源,使用属性dataPath指定源绑定属性,使用属性property指定目标的被绑定属性。接下来,我们开始把数据源的属性Id绑定到标签searchResults_ID的text属性上,把数据源的属性Name绑定到标签searchResults_Name的text属性上,把数据源的属性Address绑定到标签searchResults_Address的text属性上。在第一个绑定中,我们引入了一种Add类型的转换器(还有许多转换器,请参考位于文件PreviewScript.js内的类Sys.Preview.BindingBase的代码部分)。另外,由于控件DataTable暴露的DataIndex属性值是从0开始的,通过使用Add类型转换器可以自动导致其值加1,这更适合于大多数用户的习惯。最后的
观看运行结果
毋庸多言,请观看图3中的运行时刻结果快照吧!
![]() |
| 图3:示例1的运行时刻快照 |
在此,当示例程序启动时,数据绑定自动发生;之后,客户端控件ListView把相应于服务器端的数据展示到客户端屏幕上。




