随笔-254  评论-3298  文章-48  trackbacks-74

Flex与.NET互操作(三):基于WebService的数据访问(下)

     在上一篇文章《Flex与.NET互操作(二):基于WebService的数据访问(上) 》中介绍了通过<mx:WebService>标签来访问Webservice。实际上我们也可以通过编程的方式动态的访问WebService,Flex SDK为我们提供了WebService类。

     使用WebService类来访问WebService其实也就是将<mx:WebService>标签的属性通过类对象的属性形式来表示,相比之下使用WebService类比使用<mx:WebService>标签要灵活。下面我们来看看编程方式怎么连接和调用远程方法:

1     internal function onClick():void
2     {
3         var service:WebService = new WebService();
4         service.loadWSDL("http://localhost:1146/FlashFlexService.asmx?wsdl");
5         service.addEventListener(ResultEvent.RESULT,onResult);
6         service.addEventListener(FaultEvent.FAULT,onFault);
7         service.GetBook();
8     }

 

     直接通过类对象的loadWSDL()方法调用远程WebService,动态为类对象指定相关的处理函数,然后和标签一样调用远程WebService方法既可。

1     internal function onResult(evt:ResultEvent):void
2     {
3         Alert.show(evt.result.Id);
4     }
5     
6     internal function onFault(evt:FaultEvent):void
7     {
8         Alert.show(evt.fault.faultDetail.toString());
9     }

 

     如上便完成了使用WebService类通过编程的方式访问远程WebService方法的调用。

     下面来看看WebService返回DataTable等负责类型,在Flex客户端该怎么解析。首先定义WebService方法如下:

 1 [WebMethod(Description="该方法将返回DataTable类型的数据")]
 2 public DataTable GetDataTable()
 3 {
 4     DataTable dt = new DataTable("Books");
 5     dt.Columns.Add("Id"typeof(int));
 6     dt.Columns.Add("Name"typeof(string));
 7     dt.Columns.Add("Author"typeof(string));
 8     dt.Columns.Add("Price"typeof(double));
 9 
10     DataRow dr = dt.NewRow();
11     dr["Id"= 1;
12     dr["Name"= "《Flex游戏开发》";
13     dr["Author"= "张三";
14     dr["Price"= 54.85;
15     dt.Rows.Add(dr);
16 
17     dr = dt.NewRow();
18     dr["Id"= 2;
19     dr["Name"= "《Flash游戏开发》";
20     dr["Author"= "李四";
21     dr["Price"= 65.50;
22     dt.Rows.Add(dr);
23 
24     return dt;
25 }

 

     同样在Flex客户端通过WebService来访问就可以了,下面是使用<mx:WebServive>标签访问(这里需要注意,<mx:operation>标签的name必须与服务端的WebService方法同名):

1     <mx:WebService id="myService" 
2         wsdl="http://localhost:1146/DataWebService.asmx?wsdl" useProxy="false">
3         <mx:operation name="GetDataTable">
4         </mx:operation>
5     </mx:WebService>

 

     提供好了WebService,客户端也连接上了WebService,现在只差调用WebService提供的远程方法了。如下:

 1     internal function onTable():void
 2     {
 3         myService.addEventListener(ResultEvent.RESULT,onSuccess);
 4         myService.addEventListener(FaultEvent.FAULT,onFault);
 5         myService.GetDataTable.send();
 6     }
 7     
 8     internal function onSuccess(evt:ResultEvent):void
 9     {
10         //bookGrid.dataProvider=this.myService.GetDataTable.lastResult.Tables.Books.Rows;
11     }
12     
13     internal function onFault(evt:FaultEvent):void
14     {
15         Alert.show("调用WebService方法失败,详细:" + evt.fault.faultDetail.toString());
16         
17     }

 

     将WebService的返回值绑定在Flex的DataGrid组件,mxml的相关代码如下:

 1 <mx:Panel x="41" y="123" width="480" height="279" layout="absolute" fontSize="12">
 2     <mx:DataGrid x="10" y="10" width="436" id="bookGrid" 
 3         dataProvider="{this.myService.GetDataTable.lastResult.Tables.Books.Rows}">
 4         <mx:columns>
 5             <mx:DataGridColumn headerText="编号" dataField="Id"/>
 6             <mx:DataGridColumn headerText="书名" dataField="Name"/>
 7             <mx:DataGridColumn headerText="作者" dataField="Author"/>
 8             <mx:DataGridColumn headerText="价格" dataField="Price"/>
 9         </mx:columns>
10     </mx:DataGrid>
11     <mx:ControlBar>
12         <mx:Button label="DataTable" click="onTable()"/>
13     </mx:ControlBar>
14 </mx:Panel>

 

     通过DataGrid的dataProvider属性绑定DataGrid组件的数据源,除了直接通过"{}"绑定表达式帮定外我们也可以在调用远程方法成功的处理函数里给DataGrid指定数据源,见上面代码中注释的代码部分。{this.myService.GetDataTable.lastResult.Tables.Books.Rows}表示将远程WebService方法GetDataTable()的返回结果(DataTable)的所有行作为数据源与DataGrid组件进绑定,其中Books为数据源DataTable的name,详细见前面WebService方法的定义出。程序运行结果如下图:

         

     

     DataSet,DataTable相比泛型集合来说,性能上有很大的差距,复杂的序列化和反序列化过程也很负责,自从.net 2.0推出泛型到现在,我一直就比较喜欢用泛型来传递大数据。OK,下面我将介绍下在Flex中怎么去处理WebService方法返回的泛型集合数据。我们有如下WebService方法定义:

 

 1     [WebMethod(Description="该方法返回泛型集合")]
 2     public List<Book> BookList()
 3     {
 4         return new List<Book>
 5         {
 6             new Book
 7             {
 8                 Id = 1,
 9                 Name = "《Flex游戏开发》",
10                 Author = "张三",
11                 Price = 54.85
12             },
13             new Book
14             {
15                 Id = 1,
16                 Name = "《Flash游戏开发》",
17                 Author = "李四",
18                 Price = 65.50
19             }
20         };
21     }

 

     相比DataSet,DataTable类型,使用List<>返回数据我个人认为更方面容易处理。我们直接在WebService的调试环境下测试返回List<>的WebService方法可以看到如下结果:

        

     这就是以泛型结合(List<>)的形式返回的数据形式,相比DataTable的返回结果更为简洁,明了。话说到此,我们在Flex下该怎么去获取这个返回值和处理这个值呢?其实这里已经很清楚的展现了我们可以通过什么方式去处理,仔细看上图会发现"ArrayOfBook"????这是什么东西?莫非是在客户端可以通过数组的形式得到这个返回值。为了进一步搞清楚这里面的的点点滴滴,我们需要深入到内部去了解下返回值的具体构造,通过Flex Builder的调试环境可以得到如下信息:  

          

     看清楚了吗?BookList方法的lastResult结构集下有两个对象,点开节点可知正是我们通过List<Book>返回的两个Book对象,而lastResult的类型是:mx.collections.ArrayCollection,这不真是ActionScript中的数组集合吗?好的,既然这样,在Flex客户端便可以直接通过lastResult得到WebService返回的泛型集合数据了。如下代码块:

 1 internal function onTable():void
 2 {
 3     myService.addEventListener(ResultEvent.RESULT,onSuccess);
 4     myService.addEventListener(FaultEvent.FAULT,onFault);
 5     myService.BookList.send();
 6 }
 7 
 8 internal function onSuccess(evt:ResultEvent):void
 9 {
10     var arrC:ArrayCollection = this.myService.BookList.lastResult as ArrayCollection;
11     bookGrid.dataProvider=arrC;
12 }
13 
14 internal function onFault(evt:FaultEvent):void
15 {
16     Alert.show("调用WebService方法失败,详细:" + evt.fault.faultDetail.toString());
17     
18 }

 

     对应的mxml代码如下(运行结果和上面返回DataTable类型一样):

 1 <mx:Panel x="41" y="123" width="480" height="279" layout="absolute" fontSize="12">
 2     <mx:DataGrid x="10" y="10" width="436" id="bookGrid">
 3         <mx:columns>
 4             <mx:DataGridColumn headerText="编号" dataField="Id"/>
 5             <mx:DataGridColumn headerText="书名" dataField="Name"/>
 6             <mx:DataGridColumn headerText="作者" dataField="Author"/>
 7             <mx:DataGridColumn headerText="价格" dataField="Price"/>
 8         </mx:columns>
 9     </mx:DataGrid>
10     <mx:ControlBar>
11         <mx:Button label="DataTable" click="onTable()"/>
12     </mx:ControlBar>
13 </mx:Panel>

 

     关于WebService的数据访问就介绍到这里,由于个人能力有限,文中有不足之处还望大家指正。如果有什么好的建议也可以提出,大家相互讨论,学习,共同进步!!

版权说明

  本文属原创文章,欢迎转载,其版权归作者和博客园共有。  

  作      者:Beniao

 文章出处:http://beniao.cnblogs.com/  或  http://www.cnblogs.com/

 

posted on 2009-01-15 01:08 Bēniaǒ 阅读(8266) 评论(25) 编辑 收藏

评论:
#1楼 2009-01-15 07:58 | colder[被抢注][未注册用户]
Flex也有类似于"添加服务引用"的功能, 调用SOAP11的时候基本上区别不大.

请问楼主有没有解决Guid类型的方法? 能不能用AS里的UUID去接收服务器传来的Guid?

 回复 引用   
#2楼 2009-01-15 08:28 | aierong      
呵呵

盟主的文章要顶

 回复 引用 查看   
#3楼 2009-01-15 09:01 | 二叉树      
Flex
 回复 引用 查看   
#4楼 2009-01-15 09:31 | henry[未注册用户]
@colder[被抢注]
Guid创建UIDUtil.createUID();

用MXML描述WebService很不好的一个地方就是不方便维护。

我比较喜欢用AS定义一个接口调用类,然后在需要的地方调用
public class ILogin extends HttpBase
{
public function ILogin( doc:Application, method:String="get", result:Function=null)
{
super("userlogin", doc, method, result);
}
public var UserName:String;
public var UserPWD:String;
public var ImgSN:String;
public var ImgKey:String;

}
================================================
var send:ILogin =new ILogin(Application(this.parentApplication),
"get",function(data:XML,error:Boolean){
if(!error)
{
Loginer.ID= data.LoginID;
Loginer.Name=data.LoginName;
PopUpManager.removePopUp(my);
}});
send.UserName= txtName.text;
send.UserPWD=txtPWD.text;
send.ImgKey= ic.ImageKey();
send.ImgSN=ic.ImageSN();
send.Open();

 回复 引用   
#5楼[楼主] 2009-01-15 09:48 | Bēniaǒ      
@colder[被抢注]
Flex的工作方式和Eclipse非常的类似,其下可以通过"import Web Server"来完成对WebService的引用. 个人认为还是通过编程方式访问WebService要灵活些.

 回复 引用 查看   
#6楼[楼主] 2009-01-15 09:48 | Bēniaǒ      
@aierong
3Q

 回复 引用 查看   
#7楼[楼主] 2009-01-15 09:51 | Bēniaǒ      
@ henry
可编程方式的调用肯定比写死的标签访问要灵活. 写个通用方法还可以达到代码复用.

 回复 引用 查看   
#8楼 2009-01-15 10:45 | Otis's Technology Space      
flex 接收WebService返回的DataTable的确方便,但是不知道Flex传送ArrayCollection是否也这样方便.
建议楼主再加一个Flex传送ArrayCollection或实体类到WebService的示例..

:)

 回复 引用 查看   
#9楼 2009-01-15 10:57 | 伍迷      
引用:
8 internal function onSuccess(evt:ResultEvent):void
9 {
10 var arrC:ArrayCollection = this.myService.BookList.lastResult as ArrayCollection;
11 bookGrid.dataProvider=arrC;
12 }

你这样的写法,当this.myService.BookList.lastResult 是一条记录的时候,是会报错的,不信你试试看。

 回复 引用 查看   
#10楼[楼主] 2009-01-15 11:39 | Bēniaǒ      
@伍迷
不会出错的,如果说返回的数据是DataSet或DataTable这是有可能的.如果通过集合对象返回(如上面的List<object>),只有一条数据的时候是不会报错的.
从上面测试环境调用WebService方法(返回List<Book>的方法)结果图上可以看到,集合对象返回是以标准XML返回. 下面有我的测试代码.

 回复 引用 查看   
#11楼[楼主] 2009-01-15 11:44 | Bēniaǒ      
WebService方法代码:
 1        /// <summary>
 2         /// 返回泛型集合
 3         /// </summary>
 4         /// <returns></returns>
 5         [WebMethod]
 6         public List<Book> GetBooks()
 7         {
 8             return new List<Book>{
 9             new Book
10             {
11                 Id = 1,
12                 Name = "三国演义",
13                 Author = "罗贯中",
14                 Price = 52.30
15             }};
16         }

mxml代码如下:
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
 3     <mx:WebService id="service" 
 4         wsdl="http://localhost:7123/DataWebService.asmx?wsdl" 
 5         useProxy="false">
 6         <mx:operation name="GetBooks">
 7         </mx:operation>
 8     </mx:WebService>
 9     <mx:Script>
10         <![CDATA[
11             import mx.collections.ArrayCollection;
12             import mx.rpc.Fault;
13             import mx.rpc.events.ResultEvent;
14             import mx.rpc.events.FaultEvent;
15             
16             internal function onClick():void
17             {
18                 service.addEventListener(ResultEvent.RESULT,onResult);
19                 service.addEventListener(FaultEvent.FAULT,onFault);
20                 service.GetBooks.send();
21             }
22             
23             internal function onResult(evt:ResultEvent):void
24             {
25                 var arrC:ArrayCollection = this.service.GetBooks.lastResult as ArrayCollection;
26                 bookGrid.dataProvider=arrC;
27             }
28             
29             internal function onFault(evt:FaultEvent):void
30             {}
31         ]]>
32     </mx:Script>
33     <mx:Panel x="10" y="65" width="583" height="276" layout="absolute" fontSize="12">
34         <mx:DataGrid x="10" y="10" width="543" height="178" id="bookGrid">
35             <mx:columns>
36                 <mx:DataGridColumn headerText="编号" dataField="Id"/>
37                 <mx:DataGridColumn headerText="书名" dataField="Name"/>
38                 <mx:DataGridColumn headerText="作者" dataField="Author"/>
39                 <mx:DataGridColumn headerText="价格" dataField="Price"/>
40             </mx:columns>
41         </mx:DataGrid>
42         <mx:ControlBar>
43             <mx:Button label="调用远程方法(返回泛型集合)" click="onClick()"/>
44         </mx:ControlBar>
45     </mx:Panel>
46 </mx:Application>
运行结果如下图:

 回复 引用 查看   
#12楼[楼主] 2009-01-15 11:48 | Bēniaǒ      
@Otis's Technology Space
我不推荐使用DataSet或DataTable来传输,个人比较喜欢使用数组或泛型.

 回复 引用 查看   
#13楼[楼主] 2009-01-15 13:26 | Bēniaǒ      
@Otis's Technology Space
Flex与.NET的数据传输模式其实和AJAX与ASP.NET的非常类似.如你所提的问题,Flex与.NET传递对象或集合,通过上面WebService方法返回集合到Flex客户端,可以反想到直接传递也是可行的.
ActionScript的类对象的属性如果与服务端.NET的类对象属性名完全相同,那么可以直接将ActionScript的类对象作为参数传递到WebService的WebMethod.详细可参考如下示例代码:
var b:Book = new Book();
b.Id=1;
b.Name="《三国演义》";
b.Author="罗贯中";
b.Price=52.35;
service.SetBook(b);
--------------------------------------------------------------------------------------------------------
WebService方法的定义:
[WebMethod]
public void SetBook(Book book){}


如果你要传递大量数据,可以使用ActionScript的数组或集合来传递,如下简单示例:
var array:Array = new Array();
var b:Book = new Book();
b.Id=1;
b.Name="《三国演义》";
b.Author="罗贯中";
b.Price=52.35;
array.push(b); //将b对象存入ActionScript数组队列中
array.push(b); //在放一个进去
service.SetBooks(array); //这里直接传递数组到服务端
---------------------------------------------------------------------------------------------------------
public void SetBooks(List<Book> b)
{
//......
}

 回复 引用 查看   
#14楼 2009-01-15 18:35 | Otis's Technology Space      
@Bēniaǒ
感谢回复..
看起来还真是蛮方便的..

 回复 引用 查看   
#15楼[楼主] 2009-01-15 19:19 | Bēniaǒ      
@Otis's Technology Space
~ 如果整个系统的数据全部通过WebService来访问的话也不是件好事,某些情况下使用别的方式比WebService更好。

 回复 引用 查看   
#16楼 2009-01-15 19:58 | 伍迷      
@Bēniaǒ
不知道你有没有碰到过,当记录集是一条记录的时候,返回值,把它强制转化为ArrayCollection是有问题的。
var arrC:ArrayCollection = this.service.GetBooks.lastResult as ArrayCollection;

原因是一条记录时,它的返回值是ObjectProxy



 回复 引用 查看   
#17楼[楼主] 2009-01-16 09:23 | Bēniaǒ      
@伍迷
不知道你所说的"记录集"是什么形式的,数组?集合?泛型?DataTable?DataSet?
商品评论中我给出了通过泛型返回只有一条数据不会出错.详细可以看我上面评论中给出的实例以及运行结果截图.

我还没有遇到过你说的这个错误,网上很多文章里都在说通过返回DataTable只有一条数据的时候会出错.如果使用我上面那种获取数据的方式,DataTable里只有一条数据也不会出错.可参考下面示例:

[WebMethod(Description = "返回只有一条数据的DataTable对象")]
public DataTable GetTable()
{
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"] = 52.30;
dt.Rows.Add(dr);

return dt;
}

----------------------------------------------------------------------------------------
var arrC:ArrayCollection = service.GetTable.lastResult.Tables.Book.Rows as ArrayCollection;
bookGrid.dataProvider = arrC;
其中service为的id,Book为上面所定义的DataTable名.另外我在使用DataSet的时候,返回只有一条数据在flex里转换为ArrayCollection也没出过错.

 回复 引用 查看   
#18楼 2009-02-26 18:29 | Cayenne[未注册用户]
flex可以给webservice传个对象做参数么?
 回复 引用   
#19楼[楼主] 2009-02-27 13:58 | Bēniaǒ      
@Cayenne
当然可以的.

 回复 引用 查看   
#20楼 2009-07-03 13:12 | 上的风格[未注册用户]
不错 很强大
 回复 引用   
#21楼 2011-06-22 16:00 | 羊圈里最帅的小羊      
楼主,你本章节主要重点还是在于以编程方法去获取webService数据,所以觉得在MXML中配置webservice节可以不讲那么多,对于你这个实例,我也重新设计了一下做了实验,如下:
WebService1.asmx中:
[WebMethod(Description = "返回泛类型")]
public List<Book> BookList()
{
List<Book> result = new List<Book>();
Random rnd=new Random(10);
for (int i = 1; i < 21; i++)
{
Book book = new Book();
book.ID = i;
book.Name = String.Format("《书籍{0}的名称》",i);
book.Author = String.Format("《书{0}作者》", i);
book.Price = Double.Parse((rnd.NextDouble()*100).ToString("0.00"));
result.Add(book);
}
return result;
}

public class Book
{
public int ID { get; set; }
public string Name { get; set; }
public string Author { get; set; }
public double Price { get; set; }
}

在前台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.collections.ArrayCollection;
import mx.rpc.events.ResultEvent;
import mx.rpc.soap.WebService;
import mx.controls.Alert;
internal function onClick():void
{
var service:WebService=new WebService();
service.loadWSDL("http://localhost:3035/WebService1.asmx?wsdl");
service.addEventListener(ResultEvent.RESULT,onResult);
service.addEventListener(FaultEvent.FAULT,onFault);
service.BookList();
}

internal function onResult(evt:ResultEvent):void
{
var arrC:ArrayCollection=evt.result as ArrayCollection;
bookGrid.dataProvider=arrC;
}

internal function onFault(evt:FaultEvent):void
{
Alert.show("调用WebService失败,详情:"+evt.fault.faultDetail.toString());

}
]]>
</mx:Script>
<mx:Panel x="41" y="123" width="480" height="300" layout="absolute" fontSize="12">
<mx:DataGrid x="10" y="10" width="436" id="bookGrid">
<mx:columns>
<mx:DataGridColumn headerText="编号" dataField="ID"/>
<mx:DataGridColumn headerText="书名" dataField="Name"/>
<mx:DataGridColumn headerText="作者" dataField="Author"/>
<mx:DataGridColumn headerText="价格" dataField="Price"/>
</mx:columns>
</mx:DataGrid>
<mx:ControlBar>
<mx:Button label="获取表" click="onClick()"/>
</mx:ControlBar>
</mx:Panel>

</mx:Application>

 回复 引用 查看   
#22楼 2011-11-28 20:59 | 撼地猪      
楼主 犀利啊!
 回复 引用 查看   
#23楼 2011-12-23 14:35 | 继续奋斗      
楼主,真是很感谢你,我还有个问题,就是用编程来访问使用WebService,如果有多个方法,怎么分别为每个方法添加RESULT和FAULT事件?
 回复 引用 查看   
#24楼 2012-01-11 17:01 | giser-sky      
边学习边实践。谢谢分享
 回复 引用 查看   
#25楼 2012-01-12 14:04 | 无浪幻尘[未注册用户]

博主,看了你写的flex与.net webservice交互后,有些模糊的地方想想请教一下你。
1.在你的Flex与.NET互操作(二):基于WebService的数据访问(上)中,是通过WebService访问的。这个时候你调用.net指定方法时是用dataService.HelloWorld()发送请求的,也就是直接调了一下方法;如果要传送参数的也是通过dataService.ConvertToUpper("abcdefg")发送的,
但是在你的Flex与.NET互操作(三):基于WebService的数据访问(下) 中,myService.GetDataTable.send(),为什么又用这种方式发送呢,service.方法名(参数)跟service.方法名.send()到底有啥区别呢?
还有就是你在as写代码的方式为啥又在标签里面写 <mx:WebService id="myService"
2 wsdl="http://localhost:1146/DataWebService.asmx?wsdl" useProxy="false">
3 <mx:operation name="GetDataTable">
4 </mx:operation>
5 </mx:WebService>
呢,指定方法为什么不在as中代码指定呢,我就是想看看通过代码怎么指定方法

2.在你的
Flex与.NET互操作(四):使用HttpService、URLReqeust和URLLoader加载/传输数据中你用的是HttpService的
internal function onClick():void
2 {
3 var service:HTTPService = new HTTPService();
4 service.url = "http://localhost:1146/Data/Book.xml";
5 service.useProxy = false;
6 service.resultFormat="e4x";
7 service.addEventListener(ResultEvent.RESULT,onResultHandler);
8 service.send();
9 }
这里面你为啥没有指定方法呢,直接用的HTTPService.send(),为啥呢,如果说用HTTPService ,但是也指定方法,并且有要传递参数,怎么用呢,是在as中写代码的方式,不是用标签
希望博主能不嫌烦,能够回复我一下,看着你写的不一样的我有点晕了。。。

 回复 引用   
发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 1375896 6CvtQKV7lAQ=
微软最有价值专家(MVP)

微软技术社区精英(CNTAC)

2010年IT博客大赛50强

微软最有影响力开发者(GDI)


Bing Maps开发一群:75662563
微软技术群-重庆站:97035589
RIA技术联盟QQ群:26917590
昵称:Bēniaǒ
园龄:4年6个月
荣誉:推荐博客
粉丝:408
关注:26

随笔分类(285)

文章分类(14)

积分与排名

  • 积分 - 760874
  • 排名 - 60

最新评论