用FluorineFx庫實(shí)現(xiàn)Silverlight遠(yuǎn)程過程調(diào)用
Silverlight中數(shù)據(jù)訪問的實(shí)現(xiàn)方式非常之多,可以直接通過HTTP頁面提供訪問接口,也可以通過WebService、WCF以及其他的相關(guān)技術(shù)來實(shí)現(xiàn)。在MIX 09上,Nikhil Kothari發(fā)布了微軟的一神作——Microsoft .NET RIA Services,主要用來提供RIA應(yīng)用的數(shù)據(jù)訪問服務(wù),詳細(xì)可以查閱博友 流牛木馬 的《Microsoft .NET RIA Services快速上手 》這篇文章。在開源項(xiàng)目FluorineFx庫中也提供了供Silverlight實(shí)現(xiàn)RPC的類庫,究竟誰的傳輸效率高呢這里暫不討論,本文作重介紹如何使用FluorineFx Silverlight庫去實(shí)現(xiàn)Silverlight遠(yuǎn)程過程調(diào)用(RPC)。
本文實(shí)例程序開發(fā)環(huán)境:Microsoft Visual Studio 2008 + SP1、.net framework 3.5 + SP1、 Silverlight 3 Beta、FluorineFx v1.0.0.15 。本文最終的項(xiàng)目解決方案如下圖:

一、在Silverlight中的網(wǎng)絡(luò)安全訪問限制
如果連接請(qǐng)求是從 WebClient 或 HTTP 類到某個(gè)跨域站點(diǎn)的,則 Silverlight 2 運(yùn)行時(shí)將使用 HTTP 協(xié)議嘗試下載安全策略文件。Silverlight 2 運(yùn)行時(shí)首先嘗試使用 HTTP 協(xié)議下載所請(qǐng)求目標(biāo)域的根目錄下名為“clientaccesspolicy.xml”的 Silverlight 策略文件。如果返回 Silverlight 策略文件(即使在分析該文件時(shí)出現(xiàn)錯(cuò)誤),則在 Silverlight 應(yīng)用程序的整個(gè)會(huì)話期間,此文件將用作該跨域請(qǐng)求以及針對(duì)該服務(wù)器的所有后續(xù)請(qǐng)求的策略文件。如果找不到 Silverlight 策略文件,則 Silverlight 2 運(yùn)行時(shí)嘗試使用 HTTP 協(xié)議下載所請(qǐng)求目標(biāo)域的根目錄下名為“crossdomain.xml”的 Flash 策略。
- < ?xml version="1.0" encoding="utf-8"?>
 - < ACCESS-POLICY>
 - < CROSS-DOMAIN-ACCESS>
 - < ALLOW-FROM http-request-headers="*">
 - "
 - < /ALLOW-FROM>
 - < GRANT-TO>
 - < RESOURCE include-subpaths="true" path="/" />
 - < /GRANT-TO>
 - < /CROSS-DOMAIN-ACCESS>
 - < /ACCESS-POLICY>
 
二、基與FluorineFx庫的遠(yuǎn)程調(diào)用服務(wù)接口
接下來創(chuàng)建FluorineFx類庫,提供遠(yuǎn)程訪問服務(wù)接口(RemotingService),并提供相應(yīng)的方法讓Sliverlight客戶端通過FluorineFx通信網(wǎng)關(guān)實(shí)行RPC調(diào)用。
- namespace ServiceLibrary
 - {
 - [RemotingService]
 - public class DataService
 - {
 - public DataService()
 - {
 - }
 - [DataTableType("Book", "ServiceLibrary.Book")]
 - public DataTable GetBookTable()
 - {
 - DataTable dt = new DataTable("Book");
 - dt.Columns.Add("ID", typeof(int));
 - dt.Columns.Add("Name", typeof(string));
 - dt.Columns.Add("Author", typeof(string));
 - dt.Columns.Add("Price", typeof(double));
 - DataRow dr = dt.NewRow();
 - dr["ID"] = 1;
 - dr["Name"] = "《三國演義》";
 - dr["Author"] = "羅貫中";
 - dr["Price"] = 100.00;
 - dt.Rows.Add(dr);
 - dr = dt.NewRow();
 - dr["ID"] = 2;
 - dr["Name"] = "《西游記》";
 - dr["Author"] = "吳承恩";
 - dr["Price"] = 200.00;
 - dt.Rows.Add(dr);
 - dr = dt.NewRow();
 - dr["ID"] = 3;
 - dr["Name"] = "《水滸傳》";
 - dr["Author"] = "施耐庵";
 - dr["Price"] = 300.00;
 - dt.Rows.Add(dr);
 - dr = dt.NewRow();
 - dr["ID"] = 4;
 - dr["Name"] = "《紅樓夢(mèng)》";
 - dr["Author"] = "曹雪芹";
 - dr["Price"] = 400.00;
 - dt.Rows.Add(dr);
 - return dt;
 - }
 - }
 - }
 
三、使用FluorineFx網(wǎng)站宿主FluorineFx遠(yuǎn)程服務(wù)
供遠(yuǎn)程訪問(RemotingService)接口完成后,還需要建立一個(gè)FluorineFx網(wǎng)站,用來承載這個(gè)接口的遠(yuǎn)程服務(wù)。并同時(shí)配置AMF通信的信道(在services-config.xml中配置)。 
- < CHANNELS>
 - < CHANNEL-DEFINITION id=my-amf class=mx.messaging.channels.AMFChannel>
 - < ENDPOINT uri="< A href=" Gateway.aspx? {context.root} {server.name}:{server.port} http:>http://{server.name}:{server.port}/{context.root}/Gateway.aspx" class="flex.messaging.endpoints.AMFEndpoint"/>
 - < PROPERTIES>
 - < /CHANNEL-DEFINITION>
 - < /CHANNELS>
 
然后運(yùn)行這個(gè)網(wǎng)站以得到客戶端RPC訪問時(shí)所需要的網(wǎng)關(guān)地址,這里是本地測(cè)試。如果部署到服務(wù)器上則根據(jù)實(shí)際的部署信息(服務(wù)器IP/網(wǎng)站域名等)訪問。本地網(wǎng)關(guān)地址:http://localhost:3103/WebHost/Gateway.aspx。通過FluorineFx控制臺(tái)測(cè)試便可以看到FluorineFx遠(yuǎn)程服務(wù)接口方法的調(diào)用情況,如下圖示:

四、創(chuàng)建Silverlight應(yīng)用程序
現(xiàn)在創(chuàng)建一個(gè)Silverlight 應(yīng)用程序,并為此應(yīng)用程序創(chuàng)建一個(gè)宿主這個(gè)應(yīng)用程序客戶端的Web應(yīng)用程序,這里的宿主Web應(yīng)用程序就直接創(chuàng)建在上面提供遠(yuǎn)程服務(wù)接口的FluorineFx網(wǎng)站中,當(dāng)然你也可以創(chuàng)建新的Web應(yīng)用程序來宿主Silverlight應(yīng)用程序客戶端。

五、通過FluorineFx的Silverlight庫實(shí)現(xiàn)Silverlight應(yīng)用的RPC
這里首先定義一個(gè)DTO(數(shù)據(jù)傳輸對(duì)象)對(duì)象Book,如下:
- namespace SilverlightApp
 - {
 - public class Book
 - {
 - public int ID { get; set; }
 - public string Name { get; set; }
 - public string Author { get; set; }
 - public double Price { get; set; }
 - public Book()
 - { }
 - }
 - }
 
在Siverlight應(yīng)用中,在舞臺(tái)上布局一個(gè)按扭,用來發(fā)起遠(yuǎn)程調(diào)用。使用DataGrid控件來顯示調(diào)用結(jié)果。
- < USERCONTROL
 - xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
 - xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 - Width="400" Height="300">
 - < CANVAS Background="DarkBlue">
 - < BUTTON
 - Canvas.Top="10" Canvas.Left="10"
 - Background="Blue" Click="Button_Click">
 - < /BUTTON>
 - < ?xml:namespace prefix = data />< data:DataGrid
 - x:Name="bookGrid" AutoGenerateColumns="True">
 - < /CANVAS>
 - < /USERCONTROL>
 
現(xiàn)在這一步很關(guān)鍵,要使Siverlight能夠成功實(shí)現(xiàn)RPC,需要使用FluorineFx所提供的Siverlight庫,不是使用FluorineFx for .NET framework,正確的是使用FluorineFx for Siverlight庫,此庫位于FluorineFx的安裝目錄x:\FluorineFx\Bin\net\Silverlight2.0\FluorineFx.dll。庫類封裝了Siverlight實(shí)現(xiàn)RPC的相關(guān)API。
- void onNetStatus(object sender, NetStatusEventArgs e)
 - {
 - string code = e.Info["code"] as string;
 - }
 
和Flex開發(fā)一樣,同樣使用NetConnection的call()方法去調(diào)用遠(yuǎn)程服務(wù)方法,不同的是Siverlight中沒有Resonder去處理方法的返回結(jié)果,而是需要自己定義一個(gè)回調(diào)處理程序去處理返回結(jié)果,此處理程序必須實(shí)現(xiàn)接口IPendingServiceCallback,詳細(xì)如下:
- private void Button_Click(object sender, RoutedEventArgs e)
 - {
 - nc.Call("ServiceLibrary.DataService.GetBookTable", new RpcResultHandler(this));
 - }
 - public void Bind(IList list)
 - {
 - Dispatcher.BeginInvoke(delegate()
 - {
 - this.bookGrid.ItemsSource = list;
 - });
 - }
 - namespace SilverlightApp
 - {
 - public class RpcResultHandler : IPendingServiceCallback
 - {
 - MainPage page;
 - public RpcResultHandler(MainPage ctl)
 - {
 - page = ctl;
 - }
 - #region IPendingServiceCallback Members
 - public void ResultReceived(IPendingServiceCall call)
 - {
 - object result = call.Result;
 - ArrayCollection items = result as ArrayCollection;
 - IList list = new List();
 - foreach (var item in items)
 - {
 - IDictionary dic = (((FluorineFx.ASObject)(item))) as IDictionary;
 - string Name = dic["Name"].ToString();
 - Book book = new Book
 - {
 - ID = int.Parse(dic["ID"].ToString()),
 - Name = dic["Name"].ToString(),
 - Author = dic["Author"].ToString(),
 - Price = double.Parse(dic["Price"].ToString())
 - };
 - list.Add(book);
 - }
 - page.Bind(list);
 - }
 - #endregion
 - }
 - }
 
IPendingServiceCallback接口中的ResultReceived()方法專門用來處理RPC調(diào)用的結(jié)果,這里將返回結(jié)果通過相應(yīng)的解析處理后回調(diào)Siverlight應(yīng)用中的Bind()方法,實(shí)現(xiàn)將返回的結(jié)果綁定到Siverlight控件DataGrid上。程序運(yùn)行截圖:

FluorineFx庫參考文獻(xiàn):http://blog.fluorinefx.com/?p=17
本文示例代碼下載:RPCSolution.rar
【編輯推薦】















 
 
 







 
 
 
 