前两天研究了一下Flex与.NET如何进行数据交互,并写了一个文档,后面叙述得还不是很详细,还可以再研究深一点。本文是关于Flex与 ASP.NET通过Remoting方式进行通讯的内容,过段时间有空还会把其它的通讯方式也描述一下,顺便也会把Flex3与FluorineFx数据 类型转换这方面的内容讲一下,都是通过在网上找资料和自己研究所总结出来的,应该说讲得还是很浅,毕竟学得还不深,继续努力学习! 一、软件: 1、Flex平台:Adobe Flex Builder 3 2、.Net平台:Visual Studio .Net 2008 3、Remoting网关:Fluorine 4、第三方组件:RemoteObjectAMF0 二、介绍: 1、Fluorine是一种开源的AMF(ActionScript Messaging Formatter)网关,专门负责Flex3.0与.Net交互时的数据类型转换。Fluorine现支持ActionScript 2.0和ActionScript 3.0,所以Fluorine也可作为Flash与.Net交互时的AMF网关。 2、RemoteObjectAMF0组件是一种基于MXML的第三方组件,用于连接AMF网关。 3、好处: (1)交互时数据类型的自动转换。因为Flex与.NET的数据类型是不同的,例如Flex的Date与.NET中的DateTime类型。这样就导致Flex与.NET进行数据交互过程中必须进行数据类型的转换。这种数据类型的转换我们可以自己通过编写相关的代码来实现,例如在Flex及.NET中编写一个实体类对其取得的数据进行类型转换。而利用Fluorine这种网关来实现数据交互的话,它能够实现.NET与Flex中的数据类型的自动对应转换,这样从一定程度上就减轻了我们对其数据类型处理的烦恼。 (2)交互效率的提高:利用网关进行数据交互的话,它使得Flex能够直接与.Net的数据处理类进行通信,而不必像再通过另一层中间数据交互层来实现,从一定程度上它的交互效率会提高很多。 (3)这是一个开源的网关。 三、基本配置 1、服务器端的搭建: (1)安装FluorineFx,安装完后在目录中会有“Source”及“Samples”两个文件夹,“Samples”文件夹中包含了一些在VS.Net环境中使用Fluorine的例子。“Source”文件夹中包含了有关Fluorine的源代码。(代码未具体去研究) (2)安装好Fluorine之后,系统自动在VS.Net 2008新建网站中增加一个模板:FluorineFx ASP.NET Web Application。选择该模板,创建一个.NET网站。 图3.1 a)打开Visual Studio 2008,分别选择 文件 -> 新建 -> 网站 c)运行项目,获取.NET自带服务器生成的端口,及网址,本项目中是 http://localhost:4166/FluorineTest/ (3)利用VS的模板进行创建后,系统会自动加载一些引用,以及创建相关文件,并进行简单配置。创建完后的项目结构如图所示: 图3.2 “Bin”中的Dll就是用Fluorine的源文件所生成的程序集,“Templates”是一些模板。“WEB-INF/flex”中包含了XML都是些配置文件。“Gateway.aspx”是个空页面,其网页地址就是Fluorine的网关地址。 2、客户端的配置: 客户端的配置有三种方法,一种是通过向导来设置参数,从而创建Flex;另一种是通过指定services-config.xml配置文件来设置;第三种是利用第三方组件RemoteObjectAMF0来连接,这种方式就不用再去配置services-config.xml。(推荐用第三种方法) (1)向导设置方法: 步骤1. 新建Flex工程。选择ColdFusion Flash Remoting。如图3.3: 步骤2. 配置服务器。Deployed to J2EE server。如图3.4: (2)services-config.xml配置文件来设置 修改工程的属性,如图3.5: 修改“Additional compiler arguments”,设置services-config.xml配置文件的路径,可以指向刚才建立的VS.Net项目中的“WEB-INF/flex”中的services-config.xml路径。也可以将services-config.xml这个文件拷贝到调用文件的同级目录中,然后如上面所设。 (3)利用第三方组件RemoteObjectAMF0来连接,这种方法讲到时再进行介绍。 四、通信过程 1、在VS.Net中编写数据处理类HelloWorld.cs文件(可以新建一个FluorineFx ServiceLibrary类库文件,将所有的数据处理类放到库中上,然后在网站中调用此类库,这里就不创建了)。HelloWorld.cs文件的代码如下所示: using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using FluorineFx; namespace FluorineHelloWorld { /// <summary> ///HelloWorld 的摘要说明 /// </summary> [RemotingService()] public class HelloWorld { public HelloWorld() { // //TODO: 在此处添加构造函数逻辑 // } public string FromFluorine(string userName) { return "您好," + userName + "!此消息来自Fluorine Flash Remoting"; } } } RemotingService属性并不是必需的,不过使用该属性,在配置了服务浏览器的Web应用上可以通过Console.aspx查看远程服务类文件,以及调用该服务的ActionScrip。例如可以在上页类文件中设置断点,然后将Console.aspx设置为起始页,启动项目。页面会跳转到Fluorine.aspx页面,当调用FromFluorine()函数时,就会中断。下图是对函数所进行的调用结果。 图4.1 2、配置Flex工程中的services-config.xml。主要是设置这个endpoint属性。让其指向之前得到的网关地址,另外就是设置了“destination”。 <?xml version="1.0" encoding="UTF-8"?> <services-config> <services> <service id="remoting-service" class="flex.messaging.services.RemotingService" messageTypes="flex.messaging.messages.RemotingMessage"> <destination id="fluorine"> <channels> <channel ref="my-amf"/> </channels> <properties> <source>*</source> </properties> </destination> </service> </services> <channels> <channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel"> <endpoint uri="http://localhost:4166/FluorineTest/Gateway.aspx" class="flex.messaging.endpoints.AMFEndpoint"/> </channel-definition> </channels> </services-config>
3、如下创建一个MXML文件。 <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> <mx:Script> <![CDATA[ import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent; import mx.controls.Alert; public function clickBtnHelloWorld():void{ sampleRemoteObject.FromFluorine(this.txtHelloWorld.text); } public function RemoteResult(re:ResultEvent):void { var str:String = re.result as String; Alert.show(str); } public function RemoteFault(re:FaultEvent):void {Alert.show("Message:" + re.fault.faultString,"出错");} ]]> </mx:Script> <!--这里Source 对应.NET类,前面是命名空间,后面是类名 source = 命名空间.类名--> <mx:RemoteObject id="sampleRemoteObject" destination="fluorine" source="FluorineHelloWorld.HelloWorld" showBusyCursor="true"> <!--这里是.NET中的方法,name = 方法名 --> <mx:method name="FromFluorine" result="RemoteResult(event)" fault="RemoteFault(event)"/> </mx:RemoteObject> <mx:Panel horizontalAlign="center" verticalAlign="middle" width="250" height="200" layout="absolute"> <mx:TextInput x="35" y="10" id="txtHelloWorld" /> <mx:Button x="82.5" y="40" label="调用" id="btnHelloWorld" click="clickBtnHelloWorld()"/> </mx:Panel> </mx:Application> 这里创建了一个RemoteObject对象,并设置了其id属性,“destination”指向services-config.xml中的“destination”的id,source对应VS.Net类,前面FluorineHelloWorld是命名空间,后面HelloWorld是类名。“showBusyCursor”是指在交互时鼠标的状态是否为设置为繁忙。 RemoteObject中创建了一个method方法,“name”属性跟所要调用的VS.Net类中的函数名相同,“result”设置返回结果后的处理事件,“fault”设置交互过程中出错后的处理事件 。 4、运行Flex,结果如下: 图4.2 图4.3 五、使用RemoteObjectAMF0来连接fluorine网关 1、上面连接网关是利用了Flex自带的RemoteObject组件来实现,利用这个组件来实现的话,需要在创建项目时对项目进行配置,或者利用配置文档进行配置,这些在上面已经做了详细的介绍。现在介绍的是利用RemoteObjectAMF0组件来实现。这个组件是一种基于MXML的第三方组件,用于连接AMF网关,同时它是一个开源的组件。 2、下载RemoteObjectAMF0后解压,在“src”文件夹中就可以看到关于该组件的源代码,它基本上是对flex中的RemoteObject组件进行的重写。可以将“src”文件夹中的“com”文件夹全部拷贝到flex的工程中,也可以将其编译成库文件再引用到Flex工程中。 3、这时将“com”文件夹拷贝到了工程中。要使用该组件,默认情况下,要在MXML文件中的“Applications”标签中加入命名空间“xmlns:renaun="com.renaun.rpc.*"”。 4、RomoteObjectAMF0组件的定义语法如下所示: <renaun:RemoteObjectAMF0 endpoint="http://localhost:4166/FluorineTest/Gateway.aspx" id="sampleRemoteObject" source="FluorineHelloWorld.HelloWorld" showBusyCursor="true"> <renaun:methods> <renaun:method name="FromFluorine" result="RemoteResult(event)" fault="RemoteFault(event)"/> </renaun:methods> </renaun:RemoteObjectAMF0> RemoteObjectAMF0组件的“endpoint”属性指明AMF网关地址,“source”属性指明类的名称空间,<名称空间:method>组件的name属性指向类中的方法,必须与类中的定义相同,result事件处理返回的数据。 5、RemoteObjectAMF0的调用方法跟上面讲RemoteObject时差不多,比如都可以通过sampleRemoteObject.FromFluorine(this.txtHelloWorld.text);去调用.NET中的FromFluorine()方法。 六、复杂数据类型的通讯(http://xingfustar.cnblogs.com/) Remoting支持传送数组、List、HashTable、Dictionary等多种复杂数据类型,本文以数组,Dictionary,HashTable为例,讲解复杂数据类型的通讯。 (一)数组(http://xingfustar.cnblogs.com/) 1、.NET服务器端程序(http://xingfustar.cnblogs.com/) 假设我们要做段程序,来获取所有的用户姓名。修改上节中的代码,增加一个GetUsers方法。代码如下: public string[] GetArray() { string[] array = new string[]{"张三","李四","王五"}; return array; } 2、Flex客户端程序(http://xingfustar.cnblogs.com/) 在 Design 模式下添加,添加一个 Text文本控件,id为txtUsers,txt属性为空,添加一个 Button控件,id为btnGetArray,Label属性为 GetArray 在 Source 模式下, 修改 mx:RemoteObject 标签,添加 <mx:method name="GetArray" result="RemoteResult(event)" fault="RemoteFault(event)"/> 修改脚本中 RemoteResult 方法,增加一个Case条件,代码如下 public function RemoteResult(re:ResultEvent):void { switch(re.currentTarget.name) { case "HelloWord": var str:String = re.result as String; this.txtHelloWord.text = str; break; case "SayHello": str = re.result as String; this.txtSayHello.text = str; break; case "GetArray": for(var i:int=0; i<re.result.length; i++) { this.txtUsers.text += re.result[i].toString() + ", "; } break; } } 在 mx:Button (GetArray) 标签中添加属性 click="sampleRemoteObject.GetArray()" 运行Flex程序,在浏览器中查看效果 (二)Dictionary(http://xingfustar.cnblogs.com/) 1、.NET服务器端程序(http://xingfustar.cnblogs.com/) 接下来我们做个Dictionary的例子,假设上例中,我们不光要获取用户姓名,而且我们还要得到他对应的年龄,我们使用Dictionary。修改代码,添加如下方法: public Dictionary<String, Int32> GetDictionary() { Dictionary<String, Int32> age = new Dictionary<string, int>(); age.Add("张三", 23); age.Add("李四", 24); age.Add("王五", 22); return age; } 2、Flex客户端程序(http://xingfustar.cnblogs.com/) 在 Design 模式下添加,添加六个 Text文本控件,属性分别为 id = txtZhangSan,txt = ""; id = txtLiSi,txt = ""; id = txtWangWu,txt = ""; txt = "张三:"; txt = "李四:"; txt = "王五:" 添加一个 Button控件,id为btnGetDictionary,Label属性为 GetDictionary 在 Source 模式下, 修改 mx:RemoteObject 标签,添加 <mx:method name="GetDictionary" result="RemoteResult(event)" fault="RemoteFault(event)"/> 修改脚本中 RemoteResult 方法,增加一个Case条件,代码如下 public function RemoteResult(re:ResultEvent):void { switch(re.currentTarget.name) { case "HelloWord": var str:String = re.result as String; this.txtHelloWord.text = str; break; case "SayHello": str = re.result as String; this.txtSayHello.text = str; break; case "GetUsers": for(var i:int=0; i<re.result.length; i++) { this.txtUsers.text += re.result[i].toString() + ", "; } break; case "GetDictionary": this.txtZhangSan.text = re.result["张三"]; this.txtLiSi.text = re.result["李四"]; this.txtWangWu.text = re.result["王五"]; break; } } 在 mx:Button (GetDictionary) 标签中添加属性 click="sampleRemoteObject.GetDictionary()" 运行Flex程序,在浏览器中查看效果 (三)HashTable(http://xingfustar.cnblogs.com/) 1、.NET服务器端程序(http://xingfustar.cnblogs.com/) 我们将上例中的Dictionary类型改成HashTable类型,代码如下: public Hashtable GetHashTable() { Hashtable hash = new Hashtable(); hash.Add("张三", 23); hash.Add("李四", 24); hash.Add("王五", 22); return hash; } 2、Flex客户端程序(http://xingfustar.cnblogs.com/) 借用下上例内容,在 Design 模式下添加一个 Button控件,id为btnGetHashTable,Label属性为 GetHashTable 在 Source 模式下, 修改 mx:RemoteObject 标签,添加 <mx:method name="GetHashTable" result="RemoteResult(event)" fault="RemoteFault(event)"/> 修改脚本中 RemoteResult 方法,只需在上例 case "GetDictionary": 下一行加上 case "GetHashTable": 即可。 case "GetDictionary": case "GetHashTable": this.txtZhangSan.text = re.result["张三"]; this.txtLiSi.text = re.result["李四"]; this.txtWangWu.text = re.result["王五"]; break; 七、自定义实体对象的传递(http://xingfustar.cnblogs.com/) 本节是Remoting通讯的最后一节,主要讲述自定义实体对象的传递,并简单了解下Flex中类的声明及DataGrid的使用方法。我们仍分两个部分来讲。 1、.NET服务器端程序(http://xingfustar.cnblogs.com/) 首先,我们编写一个用户实体类,包括姓名、性别及年龄,类代码如下 /*---------------------------------------------------------------- * 版权:http://XingFuStar.cnblogs.com * * 文件名: User.cs * 文件功能描述: User实体类 * * 作者:XingFuStar * 日期:2007年12月11日 * * 当前版本:V1.0.0 * * 修改日期: * 修改内容: *---------------------------------------------------------------*/ using System; namespace RemotingSample { public class User { private string name; public string Name { get { return name; } set { name = value; } } private int age; public int Age { get { return age; } set { age = value; } } private string sex; public string Sex { get { return sex; } set { sex = value; } } public User() { } } } 在我们前两节编写的RemotingSample类中添加 GetUsers 方法,代码如下: public List<User> GetUsers() { List<User> users = new List<User>(); User user = new User(); user.Name = "张三"; user.Age = 23; user.Sex = "男"; users.Add(user); user = new User(); user.Name = "李四"; user.Age = 24; user.Sex = "女"; users.Add(user); user = new User(); user.Name = "王五"; user.Age = 22; user.Sex = "男"; users.Add(user); return users; } 接下来,我们开编写Flex端,重点在Flex这里 2、Flex客户端程序(http://xingfustar.cnblogs.com/) /*---------------------------------------------------------------- * 版权:http://XingFuStar.cnblogs.com * * 文件名: User.as * 文件功能描述: 用户实体类 * * 作者:XingFuStar * 日期:2007年12月14日 *---------------------------------------------------------------*/ package Module { //这名话是必须的,用这句话来绑定.Net中的类 [RemoteClass(alias="RemotingSample.User")] public class User { public function User() { //请不要删除以下信息 //版权:http://XingFuStar.cnblogs.com } private var name:String; public function get Name():String { return name; } public function set Name(setValue:String):void { name = setValue; } private var age:int; public function get Age():int { return age; } public function set Age(setValue:int):void { age = setValue; } private var sex:String; public function get Sex():String { return sex; } public function set Sex(setValue:String):void { sex = setValue; } } } 注意这个类的第一行,有这样一句话 [RemoteClass(alias="RemotingSample.User")] 这是连接.NET类的关键所在, 添加这句话后,这个类,才与.NET中创建的User类建立了联系。 <mx:DataGrid x="38" y="318" height="116" width="312" id="dgUser"> <mx:columns> <mx:DataGridColumn headerText="姓名" dataField="Name"/> <mx:DataGridColumn headerText="性别" dataField="Sex"/> <mx:DataGridColumn headerText="年龄" dataField="Age"/> </mx:columns> </mx:DataGrid> 继续添加一个Button控件,id为btnGetUsers,Label属性为 GetUsers public function RemoteResult(re:ResultEvent):void { switch(re.currentTarget.name) { case "HelloWord": var str:String = re.result as String; this.txtHelloWord.text = str; break; case "SayHello": str = re.result as String; this.txtSayHello.text = str; break; case "GetArray": for(var i:int=0; i<re.result.length; i++) { this.txtUsers.text += re.result[i].toString() + ", "; } break; case "GetDictionary": case "GetHashTable": this.txtZhangSan.text = re.result["张三"]; this.txtLiSi.text = re.result["李四"]; this.txtWangWu.text = re.result["王五"]; break; case "GetUsers": //新加部分 var userList:ArrayCollection = new ArrayCollection(); for(var j:int=0; j<re.result.length; j++) { var user:User = re.result[j] as User; userList.addItem(user); } //用来绑定DataGrid this.dgUser.dataProvider = userList; break; } } 在 mx:Button (GetUsers) 标签中添加属性 click="sampleRemoteObject.GetUsers()" 附件:源码 /*---------------------------------------------------------------- * 版权:http://XingFuStar.cnblogs.com * * 文件名: RemotingSample * 文件功能描述: .NET与Flex通讯DEMO * * 作者:XingFuStar * 日期:2007年12月11日 * * 当前版本:V1.0.0 * * 修改日期:2007年12月14日 * 修改内容:增加获取数组,Dictionary,HashTable等方法例程 *---------------------------------------------------------------*/ using System; using com.TheSilentGroup.Fluorine; using System.Collections.Generic; using System.Collections; namespace RemotingSample { [RemotingService("Fluorine sample service")] public class RemotingSample { public RemotingSample() { //请不要删除以下信息 //版权:http://XingFuStar.cnblogs.com } public string HelloWord() { return "Hello Word!"; } public string SayHello(string name) { return "Hello " + name + "!"; } public string[] GetArray() { string[] array = new string[]{"张三","李四","王五"}; return array; } public Dictionary<String, Int32> GetDictionary() { Dictionary<String, Int32> dictionary = new Dictionary<string, int>(); dictionary.Add("张三", 23); dictionary.Add("李四", 24); dictionary.Add("王五", 22); return dictionary; } public Hashtable GetHashTable() { Hashtable hash = new Hashtable(); hash.Add("张三", 23); hash.Add("李四", 24); hash.Add("王五", 22); return hash; } public List<User> GetUsers() { List<User> users = new List<User>(); User user = new User(); user.Name = "张三"; user.Age = 23; user.Sex = "男"; users.Add(user); user = new User(); user.Name = "李四"; user.Age = 24; user.Sex = "女"; users.Add(user); user = new User(); user.Name = "王五"; user.Age = 22; user.Sex = "男"; users.Add(user); return users; } } }
<?xml version="1.0" encoding="utf-8"?> <!-- * 版权:http://XingFuStar.cnblogs.com * * 作者:XingFuStar * 日期:2007年12月11日 * * 修改日期:2007年12月14日 * 修改内容:增加获取数组,Dictionary,HashTable等方法例程。 --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> <mx:Script> <![CDATA[ import mx.collections.ArrayCollection; import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent; import mx.controls.Alert; import Module.User; public function RemoteResult(re:ResultEvent):void { switch(re.currentTarget.name) { case "HelloWord": var str:String = re.result as String; this.txtHelloWord.text = str; break; case "SayHello": str = re.result as String; this.txtSayHello.text = str; break; case "GetArray": for(var i:int=0; i<re.result.length; i++) { this.txtUsers.text += re.result[i].toString() + ", "; } break; case "GetDictionary": case "GetHashTable": this.txtZhangSan.text = re.result["张三"]; this.txtLiSi.text = re.result["李四"]; this.txtWangWu.text = re.result["王五"]; break; case "GetUsers": //新加部分 var userList:ArrayCollection = new ArrayCollection(); for(var j:int=0; j<re.result.length; j++) { var user:User = re.result[j] as User; userList.addItem(user); } //用来绑定DataGrid this.dgUser.dataProvider = userList; break; } } public function RemoteFault(re:FaultEvent):void { Alert.show("Message:" + re.fault.faultString,"出错"); } ]]> </mx:Script> <!--这里Source 对应.NET类,前面是命名空间,后面是类名 source = 命名空间.类名--> <mx:RemoteObject id="sampleRemoteObject" destination="fluorine" source="RemotingSample.RemotingSample" showBusyCursor="true"> <!--这里是.NET中的方法,name = 方法名 --> <mx:method name="HelloWord" result="RemoteResult(event)" fault="RemoteFault(event)"/> <mx:method name="SayHello" result="RemoteResult(event)" fault="RemoteFault(event)"/> <mx:method name="GetArray" result="RemoteResult(event)" fault="RemoteFault(event)"/> <mx:method name="GetDictionary" result="RemoteResult(event)" fault="RemoteFault(event)"/> <mx:method name="GetHashTable" result="RemoteResult(event)" fault="RemoteFault(event)"/> <mx:method name="GetUsers" result="RemoteResult(event)" fault="RemoteFault(event)"/> </mx:RemoteObject> <mx:Text x="38" y="25" id="txtHelloWord"/> <mx:Button x="38" y="51" label="HelloWord" id="btnHelloWord0" click="sampleRemoteObject.HelloWord()"/> <mx:Text x="38" y="105" id="txtSayHello"/> <mx:Label x="38" y="131" text="name:"/> <mx:TextInput x="88" y="129" id="txtName"/> <mx:Button x="256" y="129" label="SayHello" id="btnSayHello" click="sampleRemoteObject.SayHello(this.txtName.text)"/> <mx:Text x="38" y="181" id="txtUsers"/> <mx:Button x="38" y="207" label="GetArray" id="btnGetArray" click="sampleRemoteObject.GetArray()"/> <mx:Label x="38" y="262" text="张三:"/> <mx:Text x="76" y="262" id="txtZhangSan"/> <mx:Label x="129" y="262" text="李四:"/> <mx:Text x="167" y="262" id="txtLiSi"/> <mx:Label x="218" y="262" text="王五:"/> <mx:Text x="256" y="262" id="txtWangWu"/> <mx:Button x="38" y="288" label="GetDictionary" id="btnGetDictionary" click="sampleRemoteObject.GetDictionary()"/> <mx:Button x="157" y="288" label="GetHashTable" id="btnGetHashTable" click="sampleRemoteObject.GetHashTable()"/> <mx:DataGrid x="38" y="318" height="116" width="312" id="dgUser"> <mx:columns> <mx:DataGridColumn headerText="姓名" dataField="Name"/> <mx:DataGridColumn headerText="性别" dataField="Sex"/> <mx:DataGridColumn headerText="年龄" dataField="Age"/> </mx:columns> </mx:DataGrid> <mx:Button x="38" y="453" label="GetUsers" id="btnGetUsers" click="sampleRemoteObject.GetUsers()"/> </mx:Application>
|
|