代码改变世界

深入Atlas系列:Web Sevices Access in Atlas示例(1) - 特别的访问方式

2006-10-12 14:32 Jeffrey Zhao 阅读(...) 评论(...) 编辑 收藏
  注意:部分内容已经过期,请结合《深入Atlas系列:Web Sevices Access in Atlas(7) - RTM中的客户端支持》阅读此文。

在《深入Atlas系列:Web Sevices Access in Atlas(1) - 客户端支持》里我们分析了Atlas客户端以AJAX方式访问Web Services方法所使用的基础代码,那就是Sys.Net.ServiceMethod,它提供了对于Web Service方法访问的封装。有了它,我们可以很方便地访问Web Services方法。但是在Atlas中,我们有更加方便的访问方式,在这篇文章里,我们就来讨论一下这些方法。


一、使用Sys.Net.ServiceMethod.invoke静态方法访问Web Services

如果阅读了Atlas代码之后,可以发现在客户端一些需要访问Web Services方法的类,例如AutoCompleteBehavior,它们在访问Web Services方法的时候并没有直接使用Sys.Net.ServiceMethod,而是调用了Sys.Net.ServiceMethod类的静态方法invoke。在以后的文章中我会分析Atlas客户端对Web Service方法提供代理的实现,届时也能发现,事实上在代理内部,使用的也是该静态方法。这个静态方法相当简单,不过我们还是来分析一下吧。代码如下:
Sys.Net.ServiceMethod.invoke静态方法分析

代码如想象中的简单,只是在静态方法内部构造一个Sys.Net.ServiceMethod类的对象,并调用它的invoke方法。由于Sys.Net.ServiceMethod的invoke方法提供了“神奇”的“函数重载”(详细信息请见《深入Atlas系列:Web Sevices Access in Atlas(1) - 客户端支持》的分析),因此Sys.Net.ServiceMethod.invoke静态方法也能通过两种方式调用,如下:

第一种是:
Sys.Net.ServiceMethod.invoke静态方法分析

第二种是:
Sys.Net.ServiceMethod.invoke静态方法分析

于是,以后就能使用这种比较简洁的方式访问Web Services方法了。


二、使用Declarative Syntax访问Web Services方法

深入代码可以发现各种有效的使用方式,尤其在现在这样文档极其匮乏的时期。事实上,对于使用Declarative Syntax访问Web Services的描述才是这篇文章的重点。仔细Atlas代码之后,可以发现在这样一个类:
1 Sys.Net.ServiceMethodRequest = function() {
2     ……
3 }
4 Sys.Net.ServiceMethodRequest.registerClass('Sys.Net.ServiceMethodRequest', Sys.Component);
5 Sys.TypeDescriptor.addType('script', 'serviceMethod', Sys.Net.ServiceMethodRequest);

在我之前的文章《使用Atlas创建自己的Client Control》里简单分析了一点:使用Sys.TypeDescriptor.addType方法能够为一个类提供Declarative Syntax的支持。关于这一点的具体实现方式已经超出了现在这篇文章的讨论范围,但是我会在“深入Atlas系列”的后续文章里从实现角度具体分析Atlas对于Xml Scripts的解析方式,敬请留意。:)

对于支持Declarative Syntax的类,其最重要的方法应该就是this.getDescriptor了(确切的说,这个是Sys.ITypeDescriptorProvider接口的方法。对于没有实现该接口的类,Atlas在识别其成员时使用的是别的方式。不过由于Sys.Component实现了Sys.ITypeDescriptorProvider接口,因此我们如果继承了Sys.Component,只要重载getDescriptor方法就可以了)。它提供了对于类成员的描述,Atlas在进行操作时会频繁使用这些信息,因此该方法非常重要。我们来看一下它在Sys.Net.ServiceMethodRequest中的实现:
getDescriptor方法实现

以上就是Sys.Net.ServiceMethodRequest类的成员描述,应该说还是相当直观的。

接着开始分析Sys.Net.ServiceMethodRequest类的主要成员,一些属性的get/set方法就忽略了。其实整个类唯一作用较大的方法就是this.invoke。代码如下:
this.invoke方法分析

整个Sys.Net.ServiceMethodRequest类的代码就分析完了!看得出来它只是对Sys.Net.ServiceMethod类进行了一个封装,但是就是这种简单的封装就能提供Declarative Syntax支持!原因就在于Atlas的代码已经对于解析Xml Scripts和识别一个类做了非常多的工作,我们当然就省事了。

不过在这个类中,有一个非常有意思的成员,那就是parameters属性。它是个只读属性,返回一个对象作为参数字典,我们能够对其以key - value的方式进行设置。事实上我们不是第一次遇到这个东西了。在最常用的Action之一:Sys.InvokeMethodAction就有该参数,该参数允许这样使用:
<parameters param1="value1" param2="value2" ... />

很自然,我们的parameters属性也能如此使用。Atlas在解析Xml时对于这样的情况,会将Xml属性名和值以key - value的形式存放在该parameters对象中。

但是,这远远不够!我们为什么要在getDescripter方法中给出该属性的定义?目的不是为了给我们的代码调用(只要存在我们代码就能访问,根本无须通过这个方法获得类成员),而是为了让Declarative Syntax识别!有了类成员的描述,我们就能使用各种Action,还有Atlas的特色之一:Binding。

对了,大家应该也已经想到了,我们可以将parameters属性和“别的什么”绑定起来啊。但是先别高兴太早,因为parameters是只读属性,按照普通的方法无法将一个值赋于该属性。但是Atlas想到了这一点,它的Binding能够处理这种情况。在后面的例子中可以看到,我们可以如此使用Binding。
<bindings>
    
<binding dataContext="txtName" dataPath="text" property="parameters" propertyKey="name" />
    
<binding dataContext="txtAge" dataPath="text" property="parameters" propertyKey="age" />
</bindings>

这里使用到了目前文档中不曾记载的Binding使用方式,它用到了propertyKey。Atlas在处理Binding时,如果发现用户提供了propertyKey,则首先使用property的get方法获得这个对象的属性的值,然后再把propertyKey的值作为key,以key - value的方式设置该属性。这个做法简直就是为了parameters这样的属性量身定制的!

Sys.Net.ServiceMethodRequest类的分析到这里应该就足够了。接下来,我们通过一个例子来具体看一下该如何使用Declarative Syntax调用Web Services方法。


三、使用Declarative Syntax访问Web Services方法范例

首先,我们定义所需要使用的Web Services方法和类:
EmployeeService.asmx文件代码

每次调用AddEmployee方法会在List中增加一个Employee对象,并输出整个Employee对象。

接下来是HTML:
HTML代码

这个范例的目的是在两个文本框(txtName和txtAge)里填写一个Employee的姓名和年龄,然后点击按钮btnInvoke之后会调用Web Services方法增加一个Employee并得到一个Employee列表,然后显示在页面上。在这里,我会使用Atlas中的Sys.UI.Data.ListView控件来显示Employee列表。关于该控件的使用方式,可以参考Dflying兄的文章《使用ASP.NET Atlas ListView控件显示列表数据》。

然后就是最重要的Atlas Xml Scripts了:
Atlas Xml Scripts

我们关注一下最重要的<serviceMethod />使用吧,正如之前所提到的,我将txtName的值与name参数绑定起来,并且将txtAge的值与age参数绑定起来,就是这么简单。

嗯,先不急着运行,是不是看出什么问题来了?对,我们为什么没有将employeeService的result属性和listView的data属性绑定起来的呢?否则我们如何获得数据呢?其实我也想,这可以说是Sys.Net.ServiceMethodRequest的一个Bug:它在result更新是不会调用this.raisePropertyChanged方法!这样Binding怎么可能收到result更新的信息呢?对于这点我也相当无语。没有办法我们只能响应completed事件,让它调用onComplete这个javascript方法了。onComplete方法代码如下:
onComplete方法

代码非常简单,就这样起效果了。我们来看一下使用吧:

首先打开页面,会看到显示为No Data:


在文本框内输入信息并点击按钮,则可以添加一个Employee,反复多次则添加多个:




四、开发自己的Componet,完全使用Declarative Syntax访问Web Services方法

必须借助于Javascript才能完成任务,是不是总是觉得心理有点别扭?至少我是这样的。而且除此之外,Sys.Net.ServiceMethodRequest还有一个不合理的地方:它的Priority属性类型是Number,在写Xml的时候就必须把数字赋予该属性。因此,我们来修改一下它的代码,开发一下一个更好的ServiceMethodRequest吧。

本想继承Sys.Net.ServiceMethodRequest并重载invoke函数可是令人惊讶的是,我们无法这样做,因为Sys.Net.ServiceMethodRequest没有调用registerBaseMethod来注册invoke函数。虽然我们依旧可以写一个this.invoke = function() { ... }也可以正确运行,但是这个不是OO的Good Practise,因此我还是完整的写了一遍代码。

由于大部分代码和Sys.Net.ServiceMethodRequest相同,那么我就给出一小部分不同的代码吧。
Jeffz.Net.ServiceMethodRequest部分代码

可以看到,我在onMethodComplete和onMethodError方法里都加了this.raisePropertyChanged("result")的调用。于是Binding就能收到result改变的消息,重新去获得它的值了。为了让“this”引用在上面两个回调函数内被正确的指向,因此使用了Function.createDelegate方法。在我之前的文章《使用Atlas创建自己的Client Control》也提到过这一点。另外,我还将priority属性改成了Sys.Net.WebRequestPriority枚举类型,这样我们就能使用"High"和"Normal"等字样了。

等等,你还发现了什么?我将parameters属性的类型改成了Array,它的get方法也变了。这是我的一个尝试,将parameters属性变成了一个Jeffz.Net.Parameter的Collection。属性类型方面的细节涉及到对于Atlas Xml Scripts的解析,因此现在不做讨论。Jeffz.Net.Parameter很简单,代码如下:
Jeffz.Net.Parameter代码

于是,相关的Declarative Syntax也会有所改变。但是请注意,这只是我的一个尝试,这并不是一个好的做法,没有任何实用价值

我们来看一下它的使用,基本上代码没有变,只是改变了部分Atlas Xml Scripts:
Atlas Xml Scripts部分代码

可能最值得注意的就是在<listView />内使用了Binding,现在一行Javascript代码都不用写就能运行了,这就是我们所需要的!对于现在的parameters的做法,再强调一下,对于目前的问题,它没有任何实用价值

由于使用效果和上面一例完全相同,因此就不做演示了。:)


点击这里下载两个范例源文件。
点击这里查看“使用Declarative Syntax访问Web Services方法”范例效果。
点击这里查看“开发自己的Componet,完全使用Declarative Syntax访问Web Services方法”范例效果。