转 silverlight获取外部数据的另一种选择:FluorineFx
2010-07-27 17:19
357 查看
Silverlight从其它系统获取外部数据的常规途径无非下面2种:
1、直接远程加载文本或xml文件(直接请求ashx/aspx,然后在ashx/aspx上输出信息也可以归入这一类)
2、通过wcf/webService取得数据
(当然,sl跟本机的sl之间也能交换数据,但这个用处有限,此外通过socket也能拿到数据,但是socket要玩好并不容易,难度系数有点高,本文不做讨论)
而返回的数据格式,最常用的通常为"xml"、"json字符串"(或普通字符串)或"最原始的Stream"
今天在学习FluorineFx(一个开源的免费项目),并查看它的演示示例时,意外发现FluorineFx也支持silverlight!
与webService采用的soap协议不同:FluorineFx支持Adobe的AMF0,AMF3,RTMP协议,能方便的与Adobe几乎所有的通讯技术交互,这为silverlight与flash/flex交互提供了可能。(详见百度百科FluorineFXhttp://baike.baidu.com/view/1654458.htm?fr=ala0_1)
下面简单说下silverlight中使用FluorineFx的大概步骤:
基本上silverlight本身只是一种UI技术,自身并无太强的的数据处理能力(独立存储虽然提供了数据存储和检索能力,但能力实在有限),要获取数据只能借助其它系统或技术,所以我们先把其它系统做好:
1、先用VS.Net(我用的是vs2010)创建一个Library项目,起名为ServiceLib,并在里面创建一个TestLib.cs的类,代码如下:
viewsource
print?
当然,这个项目要引用FluorineFx程序集,该项目的主要用意在于把"取数据"的业务逻辑封装在这一层,以方便重用。
2、再创建一个webApplication,起名为WebApp,同样要添加FluorineFx.dll的引用
2.1然后创建一个名为Gateway.aspx的文件,这样就行了,不用添加任何多余的代码(这个文件作为调用FluorineFx的网关)
2.2在根目录下,创建目录Web-INF/flex(即二层目录),然后在flex目录下,放置一个services-config.xml,内容如下:
viewsource
print?
照抄就好了,不用管太多。基本上这个配置的作用就相当于添加wcf(svc文件)后,系统自动在web.config中增加的配置节点,用于提供一些必要的配置信息.
2.3修改web.config的httpModules节点为以下内容
viewsource
print?
2.4添加对ServiceLib项目的引用
3、最后创建一个silverlight项目,添加FluorineFx.dll引用,命名为SliverlightApp
注意:FluorineFx.dll有二个版本,一个用于webform,一个专用于silverlight(本文最后会给出下载)
通常用vs.net创建一个silverlight项目时,会提示你是否把该项目承载于一个webApplication项目中,以方便测试,这里直接指定第2步中的webApp为承载项目(即相当于webApp项目添加对SliverlightApp的引用)
在silverlight中访问FluorineFx的关键代码如下:
viewsource
print?
当然还有一个数据实体类Person.cs
viewsource
print?
4、最后回过头来,在webApp中把(创建silverlight项目时自动生成的)SliverlightAppTestPage.aspx设置为启动页测试就行了
整个解决方案的目录结构如下:
分析:
传统的soap协议是采用xml格式的,而xml格式的最大问题就是数据太大,比如一个普通的"helloworld"字符串,经过xml格式封装后,可能变成<string>helloworld</string>,再加上文件头部的xml文档声明,传输数据量最终会增加不少。
为了改进,Adobe发明了AMF0/AMF3协议,AMF是Adobe独家开发出来的通信协议,它采用二进制压缩,序列化、反序列化、传输数据,从而为Flash播放器与FlashRemoting网关通信提供了一种轻量级的、高效能的通信方式。
所以FluorineFx相对于基于soap协议的webservice/wcf而言,应该是效率会更高,不过我们也应该看到微软的进步:wcf在传输数据时,除了xml格式,还可以用json格式甚至直接最原始的stream流格式。为了比较,我在代码中还特意加了test.svc以json格式返回数据,用于跟fluorinefx做下对比比(xml格式就懒得比较了,传输数据量肯定要大于json格式)--test.svc里的具体代码如下:
viewsource
print?
这是用httpwatch在firefox下测试的结果:
如果用最原始的stream方法封装json数据,返回的数据为
如果用系统提供的json自动封装,返回的数据为
而FluorineFx是以二进制返回的,不方便直接观察字符串,只能直接反序列化为Peron类,就不贴出结果了。
从运行图的Received列上可以看出:“FluorineFx返回的数据大小-375”要小于“wcf默认封装的json数据-389”,但大于“开发者自行处理的json数据大小-312”
再比较Time列,FluorineFx所用的时间是最小的(当然多测试几次,结果稍有不同,但经过我的多次观察,FluorineFx所花的时间始终是最小的)
综合比较下来:FluorineFx传输的数量小,传输时间短,整体效率是不错的,确实是silverlight/.net与其它系统高效传输数据的可选方式之一。
文中所用源代码下载:http://cid-2959920b8267aaca.office.live.com/self.aspx/Silverlight/FluorineFx.rar
1、直接远程加载文本或xml文件(直接请求ashx/aspx,然后在ashx/aspx上输出信息也可以归入这一类)
2、通过wcf/webService取得数据
(当然,sl跟本机的sl之间也能交换数据,但这个用处有限,此外通过socket也能拿到数据,但是socket要玩好并不容易,难度系数有点高,本文不做讨论)
而返回的数据格式,最常用的通常为"xml"、"json字符串"(或普通字符串)或"最原始的Stream"
今天在学习
与webService采用的soap协议不同:FluorineFx支持Adobe的AMF0,AMF3,RTMP协议,能方便的与Adobe几乎所有的通讯技术交互,这为silverlight与flash/flex交互提供了可能。(详见百度百科FluorineFX
下面简单说下silverlight中使用FluorineFx的大概步骤:
基本上silverlight本身只是一种UI技术,自身并无太强的的数据处理能力(独立存储虽然提供了数据存储和检索能力,但能力实在有限),要获取数据只能借助其它系统或技术,所以我们先把其它系统做好:
1、先用VS.Net(我用的是vs2010)创建一个Library项目,起名为ServiceLib,并在里面创建一个TestLib.cs的类,代码如下:
01 | using System.ComponentModel; |
02 | using System.Data; |
03 | using FluorineFx; |
04 |
05 | namespace ServiceLib |
06 | { |
07 | [RemotingService] |
08 | [Description( "TestService" )] |
09 | public class TestLib |
10 | { |
11 | [DataTableType( "SliverlightApp.Person" )] |
12 | public DataTableGetPersonList() |
13 | { |
14 | DataTabletbl= new DataTable(); |
15 | tbl.Columns.Add( "Name" , typeof ( string )); |
16 | tbl.Columns.Add( "Age" , typeof (System.Int32)); |
17 | tbl.Rows.Add( "菩提树下的杨过" ,30); |
18 | tbl.Rows.Add( "小龙女" ,100); |
19 | return tbl; |
20 | } |
21 | } |
22 | } |
2、再创建一个webApplication,起名为WebApp,同样要添加FluorineFx.dll的引用
2.1然后创建一个名为Gateway.aspx的文件,这样就行了,不用添加任何多余的代码(这个文件作为调用FluorineFx的网关)
2.2在根目录下,创建目录Web-INF/flex(即二层目录),然后在flex目录下,放置一个services-config.xml,内容如下:
01 | <? xml version = "1.0" encoding = "utf-8" ?> |
02 | < services-config > |
03 | < services > |
04 | < service id = "remoting-service" class = "flex.messaging.services.RemotingService" |
05 |
06 | messageTypes = "flex.messaging.messages.RemotingMessage" > |
07 | < destination id = "fluorine" > |
08 | < channels > |
09 | < channel ref = "my-amf" /> |
10 | </ channels > |
11 | < properties > |
12 | < source >*</ source > |
13 | </ properties > |
14 | </ destination > |
15 | </ service > |
16 | </ services > |
17 |
18 | < channels > |
19 | < channel-definition id = "my-amf" class = "mx.messaging.channels.AMFChannel" > |
20 | < endpoint uri = " |
21 |
22 | class = "flex.messaging.endpoints.AMFEndpoint" /> |
23 | < properties > |
24 | <!--<legacy-collection>true</legacy-collection>--> |
25 | </ properties > |
26 | </ channel-definition > |
27 | </ channels > |
28 | </ services-config > |
2.3修改web.config的httpModules节点为以下内容
1 | < httpModules > |
2 | < add name = "ScriptModule" type = "System.Web.Handlers.ScriptModule,System.Web.Extensions,Version=3.5.0.0,Culture=neutral,PublicKeyToken=31BF3856AD364E35" /> |
3 | < add name = "FluorineGateway" type = "FluorineFx.FluorineGateway,FluorineFx" /> |
4 | </ httpModules > |
3、最后创建一个silverlight项目,添加FluorineFx.dll引用,命名为SliverlightApp
注意:FluorineFx.dll有二个版本,一个用于webform,一个专用于silverlight(本文最后会给出下载)
通常用vs.net创建一个silverlight项目时,会提示你是否把该项目承载于一个webApplication项目中,以方便测试,这里直接指定第2步中的webApp为承载项目(即相当于webApp项目添加对SliverlightApp的引用)
在silverlight中访问FluorineFx的关键代码如下:
01 | using FluorineFx; |
02 | using FluorineFx.AMF3; |
03 | using FluorineFx.Messaging.Api.Service; |
04 | using FluorineFx.Net; |
05 |
06 | ... |
07 |
08 | //点击按钮时,开始调用 |
09 | private void btnFluorineFx_Click( object sender,RoutedEventArgse) |
10 | { |
11 | NetConnection_netConnection= new NetConnection(); |
12 | _netConnection.ObjectEncoding=ObjectEncoding.AMF3; |
13 | _netConnection.NetStatus+= new NetStatusHandler(_netConnection_NetStatus); |
14 | _netConnection.Connect( " ); |
15 | _netConnection.Call( "ServiceLib.TestLib.GetPersonList" , new GetPersonHandler( this )); |
16 |
17 | } |
18 |
19 | //状态回调 |
20 | private void _netConnection_NetStatus( object sender,NetStatusEventArgse) |
21 | { |
22 | string level=e.Info[ "level" ] as string ; |
23 | this .Dispatcher.BeginInvoke(()=>{ this .txtResult.Text= "level:" +level+ ",code:" +e.Info |
24 |
25 | [ "code" ] as String;}); |
26 |
27 | } |
28 |
29 |
30 | //数据回调处理 |
31 | private class GetPersonHandler:IPendingServiceCallback |
32 | { |
33 | MainPagepage; |
34 |
35 | public GetPersonHandler(MainPagepage) |
36 | { |
37 | this .page=page; |
38 | } |
39 |
40 | public void ResultReceived(IPendingServiceCallcall) |
41 | { |
42 | page.Dispatcher.BeginInvoke(()=>{page.txtResult.Text= "" ;}); |
43 | object result=call.Result; |
44 | ArrayCollectionitems=result as ArrayCollection; |
45 | foreach ( object item in items) |
46 | { |
47 | Personp=item as Person; //注意:这里直接将数据反序列化为Person了 |
48 |
49 | page.Dispatcher.BeginInvoke(()=>{page.txtResult.Text+=p.ToString()+ ";" ;}); |
50 |
51 |
52 | } |
53 |
54 | } |
55 | } |
01 | using System; |
02 |
03 | namespace SliverlightApp |
04 | { |
05 | public class Person |
06 | { |
07 | public string Name{ set ; get ;} |
08 | public int Age{ set ; get ;} |
09 |
10 | public override string ToString(){ |
11 | return "name:" +Name+ ",age:" +Age.ToString(); |
12 | } |
13 | } |
14 | } |
整个解决方案的目录结构如下:
分析:
传统的soap协议是采用xml格式的,而xml格式的最大问题就是数据太大,比如一个普通的"helloworld"字符串,经过xml格式封装后,可能变成<string>helloworld</string>,再加上文件头部的xml文档声明,传输数据量最终会增加不少。
为了改进,Adobe发明了AMF0/AMF3协议,AMF是Adobe独家开发出来的通信协议,它采用二进制压缩,序列化、反序列化、传输数据,从而为Flash播放器与FlashRemoting网关通信提供了一种轻量级的、高效能的通信方式。
所以FluorineFx相对于基于soap协议的webservice/wcf而言,应该是效率会更高,不过我们也应该看到微软的进步:wcf在传输数据时,除了xml格式,还可以用json格式甚至直接最原始的stream流格式。为了比较,我在代码中还特意加了test.svc以json格式返回数据,用于跟fluorinefx做下对比比(xml格式就懒得比较了,传输数据量肯定要大于json格式)--test.svc里的具体代码如下:
001 | using System.Collections.Generic; |
002 | using System.Data; |
003 | using System.IO; |
004 | using System.ServiceModel; |
005 | using System.ServiceModel.Activation; |
006 | using System.ServiceModel.Web; |
007 | using System.Text; |
008 |
009 | namespace WebApp |
010 | { |
011 | [ServiceContract(Namespace= "" )] |
012 | [AspNetCompatibilityRequirements(RequirementsMode=AspNetCompatibilityRequirementsMode.Allowed)] |
013 | public class test |
014 | { |
015 |
016 | ///<summary> |
017 | ///利用系统自动封装成json格式 |
018 | ///</summary> |
019 | ///<returns></returns> |
020 | [OperationContract] |
021 | [WebInvoke(Method= "GET" ,ResponseFormat=WebMessageFormat.Json)] |
022 | public List<SliverlightApp.Person>GetPersonList() |
023 | { |
024 | List<SliverlightApp.Person>lst= new List<SliverlightApp.Person>(); |
025 | lst.Add( new SliverlightApp.Person(){Name= "菩提树下的杨过" ,Age=30}); |
026 | lst.Add( new SliverlightApp.Person(){Name= "小龙女" ,Age=100}); |
027 | return lst; |
028 | } |
029 |
030 | ///<summary> |
031 | ///自己封装成json格式 |
032 | ///</summary> |
033 | ///<returns></returns> |
034 | [OperationContract] |
035 | [WebInvoke(Method= "GET" )] |
036 | public StreamGetPersonList2() |
037 | { |
038 | DataTabletbl= new DataTable(); |
039 | tbl.Columns.Add( "Name" , typeof ( string )); |
040 | tbl.Columns.Add( "Age" , typeof (System.Int32)); |
041 | tbl.Rows.Add( "菩提树下的杨过" ,30); |
042 | tbl.Rows.Add( "小龙女" ,100); |
043 | return GetStream(CreateJsonParameters(tbl)); |
044 | } |
045 |
046 |
047 | ///<summary> |
048 | ///将datatable转化成json字符串 |
049 | ///</summary> |
050 | ///<paramname="dt"></param> |
051 | ///<returns></returns> |
052 | private string CreateJsonParameters(DataTabledt) |
053 | { |
054 | StringBuilderJsonString= new StringBuilder(); |
055 | if (dt!= null &&dt.Rows.Count>0) |
056 | { |
057 | JsonString.Append( "{" ); |
058 | JsonString.Append( "\"Head\":[" ); |
059 | for ( int i=0;i<dt.Rows.Count;i++) |
060 | { |
061 | JsonString.Append( "{" ); |
062 | for ( int j=0;j<dt.Columns.Count;j++) |
063 | { |
064 | if (j<dt.Columns.Count-1) |
065 | { |
066 | JsonString.Append( "\"" +dt.Columns[j].ColumnName.ToString().Replace( "\"" , "\\\"" )+ "\":" + "\"" +dt.Rows[i][j].ToString().Replace( "\"" , "\\\"" )+ "\"," ); |
067 | } |
068 | else if (j==dt.Columns.Count-1) |
069 | { |
070 | JsonString.Append( "\"" +dt.Columns[j].ColumnName.ToString().Replace( "\"" , "\\\"" )+ "\":" + "\"" +dt.Rows[i][j].ToString().Replace( "\"" , "\\\"" )+ "\"" ); |
071 | } |
072 | } |
073 |
074 | if (i==dt.Rows.Count-1) |
075 | { |
076 | JsonString.Append( "}" ); |
077 | } |
078 | else |
079 | { |
080 | JsonString.Append( "}," ); |
081 | } |
082 | } |
083 | JsonString.Append( "]}" ); |
084 | return JsonString.ToString(); |
085 | } |
086 | else |
087 | { |
088 | return null ; |
089 | } |
090 | } |
091 |
092 | ///<summary> |
093 | ///辅助方法,用于输出流 |
094 | ///</summary> |
095 | ///<paramname="str"></param> |
096 | ///<returns></returns> |
097 | private StreamGetStream( string str) |
098 | { |
099 | MemoryStreamms= new MemoryStream(); |
100 | StreamWritersw= new StreamWriter(ms); |
101 | sw.AutoFlush= true ; |
102 | sw.Write(str); |
103 | ms.Position=0; |
104 | WebOperationContext.Current.OutgoingResponse.ContentType= "text/plain" ; |
105 | return ms; |
106 | } |
107 | } |
108 | } |
这是用httpwatch在firefox下测试的结果:
如果用最原始的stream方法封装json数据,返回的数据为
如果用系统提供的json自动封装,返回的数据为
而FluorineFx是以二进制返回的,不方便直接观察字符串,只能直接反序列化为Peron类,就不贴出结果了。
从运行图的Received列上可以看出:“FluorineFx返回的数据大小-375”要小于“wcf默认封装的json数据-389”,但大于“开发者自行处理的json数据大小-312”
再比较Time列,FluorineFx所用的时间是最小的(当然多测试几次,结果稍有不同,但经过我的多次观察,FluorineFx所花的时间始终是最小的)
综合比较下来:FluorineFx传输的数量小,传输时间短,整体效率是不错的,确实是silverlight/.net与其它系统高效传输数据的可选方式之一。
文中所用源代码下载:
相关文章推荐
- silverlight获取外部数据的另一种选择:FluorineFx
- swing jtable绑定数据库 获取用户选择行的数据
- oracle外部表,为你保存数据提供了另类的选择
- SilverLight商业应用程序开发---学习笔记(6)从服务器中获取数据之二
- jsp静态数据获取后台传来的值选择默认
- searchlookupedit的选择以及行数据的获取
- 获取jqGrid中选择的行的数据
- C#获取外部程序ListView中的数据
- Spinner获取SQLite数据库数据生成自定义下拉框(下拉选择收货地址)
- IDEA快捷键设置,选择Eclipse风格的快捷键,自动补全快捷键,关闭当前窗口快捷键Ctrl+W,自动导入设置,引入外部的jar的方式,设置项目字体,设置项目字符集,Maven的方式获取jar
- ASP小偷(远程数据获取)程序的入门教程 选择自 arcow 的 Blog
- DevExpress GridControl Gridview RepositoryItemCheckEdit复选框及获取选择行数据
- 另一种对外部样式表的获取、修改方法
- 如何获取jqGrid中选择的行的数据
- 获取jqGrid中选择的行的数据
- 从外部获取一个edit框内数据的几种思路
- Python+selenium之获取文本值和下拉框选择数据
- SilverLight商业应用程序开发---学习笔记(5)从服务器中获取数据之一
- jquery 选择input的checkbox属性 获取checkbox的值 用异步传输数据 返回结果
- Silverlight获取DataGrid选中的行数据