随笔- 26  评论- 139  文章- 1 

Gadget开发实战总结 1 (Gadget调用WebService)

前言

好久没有来这里说话了,前段时间做了一个用到Vista Gadget的项目,难得用从未接触过的技术来做东西,自然有不少收获跟体会,跟大家分享~

本文阐述了一些我们在完成这个Gadget项目中遇到的问题,希望和大家一起探讨一下Gadget的开发和应用。

准备

前段时间Csdn搞了Gadget开发大赛,摆明了就是MS宣传它的新东西。当时自己一没什么好的创意,二也没什么时间来研究这东西。不过Gadget大赛中后来获奖一些作品还是给我留下了挺深的印象。

这回暑假在做学校里的比赛,正好碰到一个应用感觉很合适用Gadget来做,几番评估之后,决定用Gadget来做,也算是给MSVista做做广告^_^

大概介绍一下我们所要做的应用。服务端计划使用.net平台实现,有已经封装好的数据访问架构,客户端计划使用Gadget,除了一般的信息浏览之外,我们希望客户端还能够完成客户的登录注销等操作。在用户登录后,客户端有需要频繁和服务端进行数据的双向交互,并且还需要进行一些数据的本地保存操作。整个模式可以类比一下QQ~不过我们的客户端是Gadget

开始

在学校里做东西,不同于企业开发,边学边做是肯定的了~在明确了客户端的需求之后,我们开始寻找Gadget的开发资料,这其中包括了MSDN中的Gadget开发文档,还有一些如Gadget开发白皮书一类的东西。网上资料很多,cnblogs也是个好地方~

经过不是很长时间的学习,我们已经搞清楚了Gadget的模式,它本身其实就是一个特殊的“网页”,逻辑通通用JS控制。不同的只是这个网页中可以使用System.Gadget等一些特殊的类。

与此同时,服务端的开发进度也很快,系统需要的一些业务逻辑和界面逻辑很快就实现了。

一切看起来还算顺利,这时候开发进度表上感觉很好,应该没几天就可以完成开发了。不过问题还是出现了~~

第一个问题数据交换

刚开始的问题主要出在Gadget和服务端的数据交换方式上。

怎么访问服务器?

根据我们找到的一些Gadget代码分析,Gadget和服务端交互主要有两种方式:

1.         使用AJAX,也就是用HttpRequest这个东西在后台发送对服务端的请求,获取服务端数据

2.         实现自己的ActiveX控件,在Javascript中调用,在ActiveX中进行和服务端的交互

Windows Vista自带的那几个Gadget程序都使用了自己的ActiveX控件,访问代码类似这样。

             try
             
{
                   
var o = new ActiveXObject("wlsrvc.WLServices");
                    stocks.msn.service 
= o.GetService("stock");
                    
if (stocks.msn.status.availability.active)
                    
{
                        stocks.msn.init();
                    }

                    
else
                    
{
                        stocks.msn.status.ping.update(
false, (stocks.msn.status.availability.error != null));
                    }

                }

 

本来我们以为那个控件提供了Gadget访问网络的方式,后来对代码的研究却发现这个叫wlsrvc.dllActiveX控件本身就封装了所有的访问逻辑。例如上面的代码:使用GetService方法只传入了一个”stock”字符串,wlsrvc就返回了一个service对象。

自带的那几个需要访问网络的Gadget都用了这个ActiveX,不同只是在于传入的初始化字符串不同,原来wlsrvc.dll只是一个Windows Vista自带Gadget专用的简单工厂

这让我们很郁闷,MS太霸道了。Wlsrvc没有任何文档,自带的Gadget连个原来是个没源代码的东西

而网上的大部分Gadget都是采用第一种方式和服务端交互的。Ajax技术已经趋向于成熟,大家都在用~

代码类似这样:

function CreatHttpRequest()
{
    ListLoading();
    HttpRequest 
= new ActiveXObject("Microsoft.XMLHTTP");
    HttpRequest.onreadystatechange 
= ListProcessResponse;
    HttpRequest.open(
"GET",”http://xxx.com/sss.ashx”,true);
    HttpRequest.setRequestHeader("If-Modified-Since","0");
    
try
    {
        HttpRequest.send();
    } 
catch (e)
    {    }
}


然后就可以通过
HttpRequest回调函数进行数据获取。

基本上就是传入一个参数,返回一个request,相信做过ajax开发的对这样的方式应该会很熟悉。

顺便说一句,在Gadget中,HttpRequest是有足够的权限直接进行跨域访问的,不会类似网页中Ajax一样跨域操作时出现“拒绝访问”的错误。

天啊,代码怎么写?

问题是:我们需要和服务器进行较多的复杂的交互,比如各种客户端数据的提交,服务端返回的数据结构也比较复杂。虽说在客户端和服务端我们都定义了一些例如UserInfo这样的实体类来进行数据的传播,但是纯粹使用HttpRequest实现这个东西来进行数据交互显然让代码变得非常的复杂。。。而且,Gadget的客户端并非WebForm那样拥有强大的服务端功能,甚至连个调试器都没有,我们一直在用Notepad++写代码

想起来一句话:AJAX让用户成了皇帝,而开发者成了奴隶。

我们预估了一下复杂度,即使使用例如Prototype这样的第三方库来简化Gadget客户端的代码编写,ashx页面的编写也是一个相当麻烦的问题。或许我们可以为每一种交互编写不同的ashx页面,但这一定不是一个好主意。很难想象服务端被做成一个拥有十几个ashx页面的网站是什么样子。即使把所有的调用统一到一个ashx页面中,这个页面中的代码也必定有着很强的耦合性(一个页面要处理十几种不同的请求),特别是客户端,需要在一个回调函数中处理十多种不同的返回值,代码的冗杂几乎也是很容易想象到的。我们想到的唯一办法就是使用设计模式让代码简洁好看一些,但Javascript这东西天生就不那么方便“搞对象”。更多的对象也只能让Javascript代码更乱。

使用WebService解决问题

上面唠唠叨叨说了大半天,也就是要阐述我们对Gadget的需求超过了一般对Gadget的定义——我们希望像做WinForm或者WebForm一样的来做Gadget程序,而一般定义的Gadget似乎只是一个简单的信息显示工具,并不会涉及复杂的逻辑。

于是我们希望使用WebService这个东西来解决这个问题。大体的思路就是服务端将接口抽象为WebService,客户端只需要调用它提供的一些函数。因为WebService基于HTTP协议,因此Javascrip理论上是完全能够调用的。

在服务端使用C#封装出一个asmx已经是如此的简单,我们几乎只需要重新抽象一遍接口,并且然后加上[WebMethod]

Gadget中调用WebService

Webservice.htc失败

下面的问题是如何使用Javascript调用WebService,没费多少力气我们就找到了一个很经典的Webservice.htc。这是一个MS出的挺完善的JS调用WebService的组件。(一个例程请参考:http://blog.csdn.net/yangyifan0/archive/2005/12/08/546923.aspx)

这时候进度一下子就拉快了,这个组件使用方法非常简单。我们的WebService没有返回通常用的DataSet而是直接返回的C#实体类,使用Soap协议访问时,实体类会被序列化成XMLjavascript可以直接的解析这些XMLJavascript的类,虽然效率不那么很高,但这样让程序变得非常简洁。

详细的用法可以参照WebService.htc的帮助文件。

好像项目就快要完成了,不过这时候令人很郁闷的事情又发生了。WebService.htc这个文件在Gadget中无论如何不起作用!~

我搞不清楚具体的原因到底是什么,感觉和安全有关,因为这个组件本身能够在网页中实现跨域进行WebService调用,似乎用了什么怪异的机制而非HttpRequest,这我并没有仔细研究,反正在Gadget中它不能用就是了。

SOAP Client成功

不知道这个时候提到 SOAP Client这个东西是不是有些做软广告的嫌疑。不过在经过一番搜索之后,我们确定了我们唯一能走的路就是自己通过HttpRequest向服务器发送SOAP,并且进行交互。又经过一番搜索之后我们找到了SOAP Client这个东西(开源的,大家可以研究研究,其实本身原理很简单)(http://www.guru4.net/articoli/javascript-soap-client/)

详细过程省略,一番调试,我们成功实现了在Gadget中调用WebService,经过再一次的封装,Javascript甚至可以像使用本地的方法一样方便的使用服务端提供的GetxxxInfo这样的方法。

最后得到的实例代码如下:

服务端:

[WebMethod(Description = "获取xxxx详细信息")]
public XxxxInfo GetXxxxInfo (XxxxQueryInfo info, string context)
{
 …
}

 

XxxxInfoXxxxQueryInfo是两个实体类,里面定义了一些如Username这样的字段供访问

客户端:

function GetXxxxInfo(sendIdentities, text, clientGuid)
{   
var pl = new SOAPClientParameters();
    pl.add(
"Identities",sendIdentities );
    pl.add(
"message",text );
    pl.add(
"clientGuid",clientGuid );
    SOAPClient.invoke(url, 
" GetXxxxInfo ", pl, true,function(r)
    {
        
//This is the Callback Function
    }) 
}

 

只是构造几个参数,写一个回调函数然后传给服务端就行了,很简单

Gadget中调用Webservice总结

Gadget中与服务器交互的方式除了自己写ActiveX控件之外似乎只能使用HttpRequest来进行页面的请求。对于一般的简单请求(比如只需要传入一个单词字符串请求一个单词的翻译),可以像一般的ajax一样实现一个ashx页面来处理请求。

如果遇到比较复杂的请求,可以考虑使用WebServiceWebService由于通过HTTP下的SOAP协议传送程序数据,所以非常合适Javascript和各种服务端的交互。但是在客户端实现SOAPJavascript的转换是需要不少代码的,如果完全自己实现,恐怕是有相当的工作量的,不过,SOAP Client这个库实现了这个工作。

这个方案只是我们经过几天的探索所得出的一些结果,至于有没有其他更好用的方法,我想应该还是有的,希望大家指教了。

休息一下

到这里为止,我阐述了在Gadget开发中遇到的客户端和服务端数据交换的问题及其解决方案。没有给出特别详细的代码,如果有看不明白的地方请指出来(我也是就偷个懒,呵呵)。

写到这里先休息一下,下面我还计划讲讲开发中遇到的其他问题以及体会,主要包括Gadget上极其困扰我们的”I See Pink” Problem以及文件操作,界面定位,时间操作等地方遇到的麻烦。




p.s 前面废话了不少来写问题的发生,其他问题本来准备一口气写完的,发现已经太长了,希望我会坚持写完后面的......

posted on 2007-09-04 19:19 Yuxin Yang 阅读(...) 评论(...) 编辑 收藏