简介
摘要
本文针对那些希望把 Silverlight 集成到解决方案中的 Java 社区开发人员,给出了一些入门指导。微软 Silverlight 是一个跨浏览器、跨平台和跨设备的浏览器插件,旨在设计、开发和发布下一代多媒体体验与富交互 (rich interface application) 的网络应用程序。 本文同时也介绍了 Silverlight 的一些背景知识,其基本功能和开发理念;介绍了在开发支持多种媒体的富客户端应用时如何合理定位 Silverlight;还介绍了 Silverlight 的架构,优点及其局限性等等。
本文探讨了 Silverlight 和 Java 交互的三种不同情况:SOAP web 服务、REST web 服务以及聚合(RSS)服务。SOAP web 服务和 REST web 服务是通过 NetBeans 中的工具来实现的。文中为每种交互都提供了演示程序代码,并且讨论了最适合应用该种交互的情况。Silverlight 也可以直接与 sockets 交互,但相对比较复杂,并不常见,因此将会在以后加以讨论。本文着重于 Silverlight 2 Beta 2 的 Silverlight-Java 交互的讨论和一些架构方面的指导。
范围
本文将主要讨论 Silverlight-Java 的互操作。通过 Visual Studio 创建一个 Silverlight 应用程序,帮助开发者对下列这些互操作方式有所了解:
- 与 SOAP web 服务的互操作
- 与 REST 服务的互操作
- 与聚合 (RSS) 服务的互操作
Silverlight 也可以与 sockets 交互,但相对比较复杂,本文将不作讨论。
终极目标
- 为 Java 社区提供实现基本的 Silverlight-Java 服务互操作的几种可选方案。
目标
- 读者对什么是 Silverlight 及其用途有准确的理解。
- 读者对 Silverlight 的架构,它的优缺点,能有个基本的了解。
- 通过对上文“范围”一节中提到的三种基本互操作实例的描述,就 Silverlight 客户端是如何与 Java 服务进行交互这个问题给读者提供一个实用的指南。
Silverlight 简介
微软 Silverlight 是个跨浏览器、跨平台、跨设备的浏览器插件,旨在设计、开发和发布下一代多媒体体验与富交互(rich interface application)的网络应用程序。Silverlight 的定位是,应用于可以快速部署到浏览器中的富互联网应用。 “Silverlight 是为连接到主机的网页内容而设计的,其特点是不但用户可深入地参与到交互中,而且应用还可在任何浏览器中运行。”使用Silverlight 的场景。
把用户界面设计和底层逻辑分开可以大大提高应用程序开发生命周期(ADLC)的生产率。结合使用 Microsoft Expression 和 Microsoft Visual Studio ,用户界面设计人员和开发人员能够发挥各自所长,改进相互间的合作。
扩展应用程序标记语言(XAML)是一种基于XML 的说明性语言,支持对流程的控制,专门用来做用户界面设计。而.NET 语言则用来编写用户界面的后台逻辑,例如VB.NET、C#、IronRuby 和IronPython。Windows Presentation Foundation (WPF) 和Silverlight 都采用XAML。
Silverlight 的运行时环境是其架构的基础。Silverlight 2 Beta 2 有一个一次性下载的大小为 4.6MB 的插件,能够部署到 IE、Firefox、Opera 或者 Safari 浏览器中。一个 zip 格式的“.xap”文件是 Silverlight 应用程序的开发包。这个“.xap”包中包含了应用程序及其接口,供 Silverlight 插件控制运行。这个“.xap”文件是在 Visual Studio .NET 中开发的,每次编译,客户端的“.xap”文件都会得到更新。Silverlight 应用程序(“.xap”文件包)可以由任何 web 服务器部署。
图 1:Web 浏览器沙箱中的 Silverlight
Silverlight 控制器内嵌在 HTML 网页中,自然就包含在 web 浏览器的沙箱内。 MSDN 有一篇技术文章 Silverlight 架构概述对 Silverlight 的架构做了大体的描述,阐释了 Silverlight 在微软用户体验 (UX) 计划中的地位。 非常重要的一点是,在 Silverlight 运行的客户端机器并不需要安装.NET。运行 Silverlight 所需的必要资源全都包含在 Silverlight 浏览器插件中。所有互操作场景都建立在 Silverlight 2 Beta 2 之上。 Silverlight 2 Beta 2 的新特性有:
- 框架语言(Visual Basic.NET, C#, IronPython, IronRuby)
- 存储分离
- JSON、REST、SOAP/WS-I、POX 和 RSS Web Services(也支持 Sockets)
- 支持 WCF
- ADO.NET 数据服务
- LINQ to Objects 和 LINQ to XML
- Deep Zoom 技术
- XML 可编程
- 媒体内容保护
- 丰富的可管理控制框架这里列举了一个简单的 crossdomain.xml 文件的例子:“
1)所有的文件头或者 2)Content-Type 和 SOAPAction 头。
如果指定 domain="*“任何领域发出的对文档的访问请求都会获得准许,但如果明确制定域名,比如 domain=”*.microsoft.com",那么只有指定领域发出的访问请求才能获得准许。Silverlight 策略文件的格式描述可以参见: Network Security Access Restrictions in Silverlight 2 “这里列举了一个简单的 crossdomain.xml 文件的例子:“ Make a Service Available Across Domain Boundaries ””。请注意本文中涉及的所有实例中,clientaccesspolicy.xml 和 crossdomain 都必须置于域的根目录下。
图 6: http://localhost:8081/clientaccesspolicy.xml
REST 服务实例
REST (REpresentational State Transfer) 这个概念是 2000 年 Roy Thomas Fielding 在他的博士论文中首先提出的。得益于 REST 本身的简单和普遍熟知的事实-万维网有 REST 架构的缘故,REST 的发展迅猛。REST 原则基于一下几点:
- 所有资源对应一个标识
- 表述 (方法) 是标准的
- 资源可有多重表述
- 资源的访问和传输由连接器封装, 连接器有: 客户端, 服务器, 缓存, 解析器和通道
- 无状态通信
REST 能够迅速流行得益于它的简单和被广泛熟知。可以简单地把 REST 看作是:通过对 URI 的操作来改变资源的状态。
“纯 REST”构想包括如下理念,即:1)所有事物都可以由拥有地址的资源来表示 2)对于资源只需要四种操作行为:创建、获取、更新和销毁。
“REST-to-HTTP 映射”,这是许多人看待 REST 的方式。这种看法和“纯 REST”的理念相同,只是 URIs 对应了资源地址,HTTP 协议的 GET、PUT、POST 和 DELETE 则对应了四种操作。
当一个 POX 服务没有遵循“纯 REST”架构,这种解决方案有时被称作“低 REST”。可能会有多种自定义的操作而不是标准的 4 种操作。自定义操作是通过 POST HTTP 方法中的参数而非 HTTP 的特定方法来完成操作。
尽管 REST 开发和维护都比较简单,但它并不处理消息安全、事务、路由以及消息,这些更象是 WS_I SOAP web 服务负责处理的事务。 Silverlight 中的 SOAP 网络服务也不处理消息安全、事务、路由以及消息。Silverlight 无法象自动生成 SOAP 代理那样来自动生成 REST 代理。
HTTP 方法
大多数REST 的实现使用了下表所示的HTTP 方法,由这些方法对底层的资源进行创建、获取、更新和销毁(CRUD)操作。
图7:HTTP 方法
Silverlight 仅支持 GET 和 POST 这两个 HTTP 方法。一些防火墙对 PUT 和 DELETE HTTP 方法的使用也设置了一定的限制。
需要指出的很重要的一点是,真正的 RESTful 的服务仅仅能够用 GET 和 POST HTTP 方法来创建(遵循了以上列出的所有 REST 规则),换句话说,REST 架构并不一定要对 HTTP 做特定的映射。 Google’s GData X-Http-Method-Override 头就是一例。
如果 web 服务在 POST 中解析 X-HTTP-Method-Override 头,那么可以在 HTTP 头中添加下列这些覆写的方法来完成 PUT 和 DELETE 操作:
- X-HTTP-Method-Override: PUT
- X-HTTP-Method-Override: DELETE
另外一个解决浏览器不支持 PUT 和 DELETE HTTP 的方法是在 Silverlight 控制器所在的页面使用异步的 JavaScript 和 XML(AJAX)。在 JavaScript 事件中使用 XMLHttpRequest 可以做到通过 HTML Bridge 在正确的时间发送正确的 HTTP 方法。MSDN 的一篇文章 HTML Bridge: Interaction Between HTML and Managed Code 详细讲解了该方法的实现。这种技术只有在 HTML 页面、“.xap”文件和服务端点在同一个领域内的时候才有效。
REST 方案的定义:WADL 和 XSD
REST 的一个局限性是 schema 是未知的,而且可能会有变化;再次验证 REST 服务可没那么简单。
Web Application Development Language(WADL)可以代替 WSDL 来支持特定的 RESTful web 服务,但目前没有得到广泛认可。
XML Schema Definition (XSD)文件可以作为 REST 服务中任何给定资源的“协议”来使用。
Java REST 支持
许多工具、框架和集成开发环境都支持 RESTful 服务的开发。NetBeans Java 集成开发环境就完全集成了 1)从实体自动产生 REST 服务 2)集成 REST 服务测试( NetBeans Getting Started with RESTful Web Services on GlassFish )。 Eclipse 集成开发环境也支持 REST 服务的开发( Eclipse REST support in STP )。 JSR 311 ,提供 RESTful Web 服务的 Java API,目前支持 HTTP 的 PUT 和 DELETE 方法。 Jersey 是遵循了 JSP311 的一个开源参考实现。
Silverlight .NET REST 支持
Silverlight 通过如下方式来支持 REST:
- Web 客户端类(例如,使用 DownloadStringCompleted(GET)和 UploadStringAsync 与 UploadStringAsync(POST)方法), 或者 HttpWebRequest 类(更难使用,但可以激活一些高阶应用)。在这个实例中我们只使用简单而直接的 WebClient 类。
- 使用上面提到的 HTML 桥
- 使用 AJAX,通过 JavaScript 和 XMLHTTP 对象或者 AJAX 工具包
创建请求URI 的技术有很多种。使用 XML 消息体时,可用 XmlSerialzer 或者 LINQ-toXml(System.Xml.Linq)。 使用 JSON 消息体时,可用 DataContractJsonSerializer 或者 LINQ-to-JSON(System.Json)。 使用 RSS/Atom 消息体时,请参照如下内容。
图 8:REST 互操作性架构
从这个 REST 的例子,我们可以理解到目前 Java REST 实现与 Silverlight 协同工作的方式,同时也可以看到这种互操作方式的局限性。NetBeans 6.1 版本能够根据 Entity 类自动生成 REST 服务。比方说,我们通过 NetBeans 创建一个简单的 REST 服务来访问某个数据库的一个数据表(也就是资源)。我们要访问的这个表 DiscountCodes,有一个 String 字段 DiscountCode 和一个 integer 字段 Rate。
图 9:表 DiscountCode
REST 动作概要:
总体来说,在这个例子中,我们用到的 HTTP 方法(REST 动作)有:
- GET: http://localhost:8081/resouces/discountCodes
- 返回所有 DiscountCode 记录的列表
- GET: http://localhost:8081/resouces/discountCodes/A/
- 返回 DiscountCode“A”
- POST: http://localhost:8081/resouces/discountCodes
- 创建一条 DiscountCode 记录
图 10:POST XML
GET: http://localhost:8081/resouces/discountCodes
这个 Silverlight 应用首先通过请求 /resource/discountCode URI 来实现“GET”(DownloadStringCompleted)操作。
图 11:GET 所有的 discountCode
我们在这里提供整个 XML 的内容,response 的内容因此一览无疑。接下来,只要在之前的 URI 基础上进一步指定 /A/,得到了一个单独的资源。
GET: http://localhost:8081/resouces/discountCodes/A/
图 12:GET 资源 /A/
POST: http://localhost:8081/resouces/discountCodes
现在通过拷贝新获得的 /A/ 资源并在 POST 文本框中创建一个资源 /D/ 来加入一个新的资源。
图 13:POST 资源 /D/
确认 GET URI 中已经添加了 /D/,然后点击 GET 按钮来创建了资源。
图 14:GET (验证) 资源 /D/
Get_Xml_Click 和 Post_Click 事件这两个事件都通过 WebClient 来与 Java 服务通信。为清晰起见,这里我们省去了例外处理的部分。
图 15:Page.xaml.cs
“Get_Click”事件中,发送的请求中包含了 getUri 文本框中的内容,而后,回复的 XML 内容则显示在 TextBox_GET 的文本框中。
“Post_Click”事件中,发送的请求中包含了 getUri 文本框中的内容,而后,回复的 XML 内容则显示在 TextBox_POST 文本框中。
图 16:Page.xml
由于在 Silverlight 既没有 PUT 也没有 DELETE HTTP 方法,因此这样的 REST 实现无法更新或者删除资源,但 REST 实现仍然可以利用 POST 方法来实现资源的更新和删除。 >Why REST Failed 一文就专门讨论了由于大多数浏览器不支持 PUT 和 DELETE 而带来的 REST 在浏览器兼容性方面的限制问题。
聚合(RSS)服务实例
远程站点聚合 2.0(RSS)是一个轻量的发布 - 订阅标准,通常订阅诸如 blog 之内的内容。RSS 最先由 Netscape 开发,而现在,RSS2.0 实际上就是 RSS 标准。原子聚合格式已经通过了 IETF 的标准化程序,并且有一个 ITEF RFC 来描述原子种子 (Atom feed) 是什么以及如何解析。大多数聚合站点都支持这两种格式。
Silverlight 有一个专为聚合而编译的动态链接库 System.ServiceModel.Syndication.dll( Silverlight Syndication )。聚合种子和聚合项都包含在这一框架中。
我们举一个“选举”的例子,客户端需要异步访问 RSS 服务种子来查看更新的种子内容。Silverlight 客户端通过种子的 URI 来访问一个简单的 Java RSS 种子。
图 17:聚合交互架构
由于结果本身就是 XML,所有 Silverlight 控件仅需要 3 行代码就能 jiexi 种子结果放到中。
图 18:聚合(RSS 2.0)阅读器
在 OpenReadCompleted 事件调用之后,回复结果被保存到 XmlReader 当中,然后被加载到 SyndicationFeed。SyndicationFeed 则以 XAML 的形式被绑定到 itemList 控件。为清晰起见,这里我们省去了例外处理的部分。
图 19: Page.xaml.cs
图 20: Page.xaml
有关 Silverlight 聚合的更多内容,请参见 Accessing Syndication Feeds with Silverlight 以及 Databinding and the SyndicationFeed class 。
SOAP Web 服务实例
Web Services Interoperability Organization (WS-I ) 定义的 web 服务标准建立在 Simple Object Access Protocol (SOAP) 基础上。SOAP 是一个基于 XML 的协议,使得消息可以通过 HTTP/HTTPS 协议来传递。W3C 的 Web Services Architecture 文件奠定了 SOAP Web 服务的基础。如果基于 Java 的 SOAP Web 服务已经存在,那么为该服务创建代理就非常直接了当,然后就好在 Visual Studio 中运用这个服务了。需要注意的是,在 web 服务中采用引入复杂的数据类型会带来很大的麻烦,尤其是在设计 Java-.NET 交互的情况下。 Java SOAP web 服务采用的数据类型应当能够映射到.NET所支持的数据类型上。
调试Web 服务也存在很多问题。像 Fiddler web 调试代理或 Web Development Helper 这样的工具在调试 Web 服务时就非常有用。
除了 WS-I Basic Profile,Silverlight 对 WS-* 不提供任何支持,“但如果自己动手实现必要的协议的话,还是可以调用这些服务的”(参见 Accessing SOAP Services )。Silverlight 支持 WS-I Basic Profile 1.0 和 SOAP 1.1 over HTTP。需要指出的是,SOAP 的错误会在客户端抛出一个例外,但不会指明导致该错误的详细信息。
Silverlight 支持 WCF(Windows Communication Foundation) 客户端技术,这种客户端可以调用 SOAP 服务,但所能调用的服务还是会受到互操作方面的限制。Silverlight 可以调用的 SOAP 服务可以是 WCF 服务、ASP.NET Web 服务(“.asmx”), 或某些 Java 服务。
Silverlight Web 服务团队的 blog 上有一篇文章—— Detailed Overview of Silverlight 2 Beta 2 Web Service Features ,概括了 Silverlight 2 Beta 2 在 web 服务方面的一些优化。对于使用 SOAP 的 Java-Silverlight 的互操作,最主要的顾虑是:代理是否能够编译;web 服务是否存在数据类型或者序列化方面的问题。
配置
ServiceReference.ClientConfig 的配置支持,使得修改绑定或地址都不需要重新编译 Silverlight 控件。
图 21:ServiceReference.ClientConfig
Windows Communications Foundation(WCF)
Silverlight 2 Beta 2 中有一个“支持 Silverlight 的 WCF 服务”模板,如果用这个模板创建 WCF 服务的话,服务自动就被配置使用 Silverlight 所支持的协议。BasicHttpBinding 使用 HTTP 之上的 SOAP1.0,是一个符合 WS-I Basic Profile 1.1 的绑定。参见“ Accessing SOAP Services ”。
ASMX
“Add Service Reference”会根据 Address:label 为所引用的服务创建一个 ASMX 代理。
图 22:添加服务引用
SOAP 错误处理
“由于 Web 浏览器的限制,客户端无法接收 SOAP 错误。当服务发送出错误时,客户端会抛出一个例外,但无法指明发生错误的详细信息。( Accessing SOAP Services )
图 23:SOAP Web 服务互操作性架构
NetBeans 中,一个简单的 web 服务节点有如下方法:FindAll 和 find。为清晰起见,这里我们省去例外处理的部分。
图 24:Page.xaml.cs
Visual Studio 中指向 Java Soap2Service 端点的代理如下:
图 25:Soap2Service 代理引用
web 服务其实就是一个调用,这个调用通过请求参数来传递,之后又负责接收 web 服务的响应。Web 服务的响应 (String) 被绑定到 XAML。而 XAML 又通过 Silverlight 控件显示到用户界面。
图 26:SOAP Web 服务 -Find All
图 27:SOAP Web 服务 - Find 'B’
代理对象有一个绑定和一个端点。代理用 findAllAsnyc 事件来发送 findAll 请求,用 FindAllCompleted 事件接收 FindAll 的响应。findAll 的响应以 XAML 显示在 findAllResponse 文本框中。为清晰起见,这里我们省去例外处理的部分。
图 28: Page.xaml.cs
图 29:Page.xaml
代理的配置信息来自 ServiceReference.ClientConfig。ServiceReferences.ClientConfig 配置文件支持多个端点的配置。
修改 ServiceReferences.ClientConfig 不需要重新编译 Silverlight 应用程序。
图 30: ServiceReferences.ClientConfig
总结
本文展开论述了 Silverlight/Java 的互操作性。简单 SOAP web 服务、REST 服务和聚合种子服务都可与 Silverlight 互操作。SOAP web 服务有着潜在的数据序列化问题,仅仅提供基本的 WS-I 支持,因此相对比较复杂,但只要 Visual Studio Silverlight 客户端中能够成功创建代理,服务也能很快实现。在开发 REST 服务的时候,开发者必须依赖于文档,而文档却可能没有更新或不是很准确。已有的的那些仅使用 GET 和 POST HTTP 方法的 RESTful 实现与 Silverllight 的互操作工作得最好。对于查询类型的服务来说,REST 是个不错的选择;而 SOAP 则更适合 CRUD 型的服务。聚合服务实现起来相对简单,而且限制很少。
开发者可以选择任意的互操作形式,找到最合适他们特定的开发和部署环境的方式。
需要了解的一个基本概念是,Silverlight 运行在浏览器上下文中。跨域、跨方案和跨区问题、浏览器连接数的限制以及对不同 MIME 类型的支持等等,对 Silverlight 和运行在浏览器平台上的任何应用来说,都是在开发和部署过程中不可忽视的问题。对于浏览器上各种各样的应用开发,最基本的共同点往往是定义浏览器局限性的基准。
非常有趣的是,在 Silverlight 2 RTM 中将很有可能支持 JAXB-style 对象引用,其支持方式与 .NET 框架 3.5 SP1(DataContractSerializer) 的支持类似。
参考资料
Silverlight
Blogs
Tim Sneath’s blog
Mike Harsh’s blog
Joe Stegman’s blog
Laurence Moroney’s blog
Tim Heur’s blog
Robert Bell’s blog
Technical
Make a Service Available Across Domain Boundaries
Silverlight HTTP Networking Stack
HTTP 1.1 Header Field Definitions
Simple Object Access Protocol (SOAP) 1.1
RFC2616 - Hypertext Transfer Protocol – HTTP/1.1
XAML
Extensible Application Markup Language (Xaml)
The New Iteration: A Whitepaper on the XAML Revolution
给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。
评论