Silverlight应用程序的数据访问与传统的应用程序有些区别。你需要搞清楚它的工作原理和它的局限性。这一章,你会看到为什么Silverlight的数据访问与众不同,同时研究Silverlight应用程序的数据访问机制。
Silverlight应用程序的数据访问
就像前面讨论的一样,RIAs消除了Windows-Based的智能客户端与Web-based应用程序的隔阂。当在RIAs这种类型的环境下时,数据访问和网络会令人迷惑。
在智能客户端里,应用程序总是能访问数据。它可以创建一个到数据库的连接,维护数据库的状态,同时保持连接。
另一方面,WEB应用程序是所谓的“伪会话”环境,意思是,在大部分情况下,是一个完全无状态和无连接的环境。客户端建立一个到服务端的请求,服务端处理请求和返回响应到客户端。响应发送完后,客户端和服务端的连接就会断开。同时服务器继续处理下一个请求。客户端和服务端之间没有维护连接和状态。
在Silverlight应用程序,我们增加了一个复杂的层。应用程序是在客户端的机器运行,仍然是无连接环境,因为它是寄宿在浏览器的。每一个请求都没有回发的概念,也不能创建一个到服务端的双向的数据处理请求。因此,数据访问被限制为几种选择。
另外,一个Silverlight应用程序有一系列的安全限制来保护保护应用程序的用户,以免应用程序获得太多的机器控制权。其中一个例子是,Silverlight应用程序只能访问隔离的存储区域来存储离线数据。它不能访问”沙箱“外的任何客户端的硬件。
那在Silverlight里有什么途径可以访问数据呢?如下:
Silverlight最普通的访问数据方式是Web服务,尤其是WCF服务。
Silverlight可以使用ADO.NET 数据服务访问数据,它是通过URI句法来访问数据的。
Silverlight 也有内置的Socket支持,它允许应用程序通过TCP Socket直接连接到服务器。
Silverlight默认支持JSON,也支持RSS2.0和Atom1.0。
这些方式中,这里会深入解析WCF服务,简单地尝试使用Sockets。
通过Web服务访问数据
这些服务可以是ASP.NET Web Service(ASMX),WCF服务或者是REST服务。
练习:使用WCF服务访问数据
这个练习修改自前面DataGrid的练习。不同的是这里会通过一个Web服务来获取数据。
看看下图可能有助回忆:
- 使用VS2010创建一个名为WCFService的Silverlight应用程序。
- 右击WCFService.Web,‘添加新项’就像前面一样添加一个名为StartingHands.cs的类,代码如下:
public class StartingHands { public string Nickname { get; set; } public string Notes { get; set; } public string Card1 { get; set; } public string Card2 { get; set; } public static List<StartingHands> GetHands() { List<StartingHands> hands = new List<StartingHands>(); hands.Add(new StartingHands() { Nickname = "Big Slick", Notes = "Also referred to as Anna Kournikova.", Card1 = "As", Card2 = "Ks" });
省略。。。。。。 return hands; } } -
接着创建一个WCF服务。在WCFService.Web中添加新项=》“启用了Silverlight的WCF服务”,名为StartingHandService.svc。
-
修改Dowork方法为GetHands,代码如下:
[OperationContract] public List<StartingHands> GetHands() { return StartingHands.GetHands(); }
-
回到WCFService项目,添加服务引用=》添加上面的WCF服务,命名为StartingHandService。
-
打开MainPage.xaml,把前面的XAMLCopy过来,它们是一样的,区别只是获取数据改为使用WCF服务。
-
打开MainPage.xaml.cs,添加如下带代码来调用WCF服务:
public MainPage() { InitializeComponent(); this.Loaded += (sender, e) => { var service = new StartingHandServiceClient(); service.GetHandsCompleted += (sender1, e1) => { this.grdData.ItemsSource = e1.Result; }; service.GetHandsAsync(); }; }
-
运行后可得到和上面一样的结果。
这个例子展示了使用VS提供的“启用了Silverlight的WCF服务”来访问远程数据。就如前面所说,这是Silverlight最普通的数据访问方式。
从其他域访问服务
前面那个例子里,WCF服务与Silverlight应用程序实在同一域的。如果要访问不同域的服务要怎么做呢?
实际上,作为最佳实践,你应该将服务和应用程序的域分离。即使服务和Silverlight应用程序都在你的控制范围内,你也应该分开不同的域处理。
如果你尝试直接在Silverlight里访问不同域的服务,你会发现是行不通的。这是因为除非在服务寄宿时允许它,默认Silverlight应用程序是不能调用其它域的服务的。Silverlight应用程序能不能访问某个确定的域,取决于在目标域的根目录的一个或两个文件:clientaccesspolicy.xml or crossdomain.xml。
首先,Silverlight会在域的根目录查找名为clientaccesspolicy.xml的文件。这是Silverlight客户端访问策略文件。如果你希望你发布的服务Silverlight应用程序能访问,就要使用这个特殊的文件,它提供了Silverlight应用程序访问策略权限的大部分选项。下面是一个简单的clientaccesspolicy.xml的例子:
<?xml version="1.0" encoding="utf-8"?> <access-policy> <cross-domain-access> <policy> <allow-from http-request-headers="*"> <domain uri="*"/> </allow-from> <grant-to> <resource path="/" include-subpaths="true"/> </grant-to> </policy> </cross-domain-access> </access-policy>最重要的元素是<allow-from>和<grant-to>。<allow-from>元素定义了可以访问<grant-to>元素规定的资源中的那些域。
如果Silverlight在想尝试访问的服务的域的根目录下找不到clientaccesspolicy.xml,就会尝试找名为crossdomain.xml的文件。这是为Flash应用程序访问跨域服务的XML策略文件,Silverlight也支持这个文件。下面是简单的例子:
<?xml version="1.0"?> <!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd"> <cross-domain-policy> <allow-http-request-headers-from domain="*" headers="*"/> </cross-domain-policy>
虽然Silverlight支持crossdomain.xml,但是使用clientaccesspolicy.xml才是最佳实践。
总结
在这一章,探讨了Silverlight应用程序通过WCF服务来访问数据,还有关于跨域访问策略文件问题。