问题:笔者在项目中需要循环一个WebService方法N次,以获得N个结果数据,但是这过程中出现了一些问题,获取到的结果数据量大于笔者的预期且值为N*N。

        Silverlight中常见的数据访问方式都是通过类似于WebService异步请求方式来获取的,相信大部分人都会这个WebService的请求 方法,但是在某一个需要输入参数获取一个结果的WebService方法中,假设我们需要循环输入N个参数,然后获取N个结果集的情况下进行的操作会出现 什么情况呢?本文将围绕循环WebService循环访问探讨一下Silverlight中的异步WebService数据请求过程。

        首先新建一个Silverlight应用程序项目,在Web项目中添加Wservice.asmx的服务页面,在页面内我们创建一个WebService 方法源码如下,输入参数为1、2、3、4、5的情况下,获得相应的结果为(参数---word)如1---word,2---word。

  1. [WebMethod] 
  2. public string GetData(int id) 
  3. string rstr = string.Empty; 
  4. rstr = id.ToString() + "---word"
  5. return rstr; 

        下面我们编写一个实体类,来绑定ListBox控件。源码如下:

  1. /// <summary> 
  2. /// 信息类 属性Id为ID值,属性Infostr为信息类的字符值 
  3. /// </summary> 
  4. public class info 
  5. int id; 
  6. string infostr; 
  7.  
  8. public int Id 
  9. get { return id; } 
  10. set { id = value; } 
  11.  
  12. public string Infostr 
  13. get { return infostr; } 
  14. set { infostr = value; } 

        下面我们在XAML文件中添加两个ListBox和两个Button控件。分别用来显示错误的多条数据的情况和正确的N条数据的情况。

 

  1. <ListBox Height="193" HorizontalAlignment="Left" Margin="61,29,0,0" Name="listBox1" VerticalAlignment="Top" Width="154" /> 
  2. <Button Content="获取25个WebService数据" Height="23" HorizontalAlignment="Left" Margin="61,240,0,0" Name="button1" VerticalAlignment="Top" Width="154" Click="button1_Click" /> 
  3. <ListBox Height="193" HorizontalAlignment="Left" Margin="264,29,0,0" Name="listBox2" VerticalAlignment="Top" Width="154" /> 
  4. <Button Content="获取5个WebService数据" Height="23" HorizontalAlignment="Left" Margin="264,240,0,0" Name="button2" VerticalAlignment="Top" Width="154" Click="button2_Click" /> 

        下面我们查看CS中的关键代码如下:

 

  1. #region 获取到错误的数据条数 条数是N*N 
  2. /// <summary> 
  3. /// 获取错误的多条数据的方法 
  4. /// </summary> 
  5. public void GetMoreList() 
  6. //清除infoMoreList数据集,然后循环访问WebService方法 
  7. infoMoreList.Clear(); 
  8. for (int i = 1; i < 6; i++) 
  9. MoreClient.GetDataAsync(i); 
  10. MoreClient.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(wClient_GetDataCompleted); 
  11. void wClient_GetDataCompleted(object sender, GetDataCompletedEventArgs e) 
  12. info inf = new info() 
  13. Id=1, Infostr=e.Result 
  14. }; 
  15. infoMoreList.Add(inf); 
  16. #endregion 
  17.  
  18. #region 获取正确的数据条数 
  19. /// <summary> 
  20. /// 获取正确数据的方法 
  21. /// </summary> 
  22. public void GetList() 
  23. //清除infoList数据集,然后循环访问WebService方法 
  24. infoList.Clear(); 
  25. for (int i = 1; i < 6; i++) 
  26. LessClient.GetDataAsync(i); 
  27. LessClient.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(wClient_LessGetDataCompleted); 
  28.  
  29. void wClient_LessGetDataCompleted(object sender, GetDataCompletedEventArgs e) 
  30. info inf = new info() 
  31. Id=1, Infostr=e.Result 
  32. }; 
  33. infoList.Add(inf); 
  34. #endregion 

        关键在于for循环之中有没有包括MoreClient.GetDataCompleted事件的加载。 

        第一种错误的情况下每次循环发出异步请求加载一次GetDataCompleted事件,一共循环五次,那么加载了5次GetDataCompleted事件的时候,也发出了5次的Ansyc(i)请求,所以5*5=25次获取事件结果数据,这是错误的!

        第二种正确的情况下每次循环发出异步的Ansyc(i)请求即可,只是在循环完之后加载一次GetDataCompleted事件即可,然后就会执行 5*1=5次获取事件结果处理。通过每刷新程序,然后按Button键得到的右边ListBox数据排列不同可以看出:发出请求的时间顺序和得到结果的时 间顺序是不一致的。

        下图展示两种情况得到的数据如下:

         本实例的所有源代码如下,点击代码展开观看:

Wservice.asmx.cs源代码
  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Linq; 
  4. using System.Web; 
  5. using System.Web.Services; 
  6.  
  7. namespace SLWebService.Web 
  8. /// <summary> 
  9. /// Wservice 的摘要说明 
  10. /// </summary> 
  11. [WebService(Namespace = "http://tempuri.org/")] 
  12. [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] 
  13. [System.ComponentModel.ToolboxItem(false)] 
  14. // 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。 
  15. // [System.Web.Script.Services.ScriptService] 
  16. public class Wservice : System.Web.Services.WebService 
  17.  
  18. [WebMethod] 
  19. public string GetData(int id) 
  20. string rstr = string.Empty; 
  21. rstr = id.ToString() + "---word"
  22. return rstr; 
MainPage.xaml源代码

  1. <UserControl xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" x:Class="SLWebService.MainPage" 
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  4. xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
  5. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
  6. mc:Ignorable="d" 
  7. d:DesignHeight="800" d:DesignWidth="800"
  8.  
  9. <Grid x:Name="LayoutRoot" Background="White"
  10. <ListBox Height="193" HorizontalAlignment="Left" Margin="61,29,0,0" Name="listBox1" VerticalAlignment="Top" Width="154" /> 
  11. <Button Content="获取25个WebService数据" Height="23" HorizontalAlignment="Left" Margin="61,240,0,0" Name="button1" VerticalAlignment="Top" Width="154" Click="button1_Click" /> 
  12. <ListBox Height="193" HorizontalAlignment="Left" Margin="264,29,0,0" Name="listBox2" VerticalAlignment="Top" Width="154" /> 
  13. <Button Content="获取5个WebService数据" Height="23" HorizontalAlignment="Left" Margin="264,240,0,0" Name="button2" VerticalAlignment="Top" Width="154" Click="button2_Click" /> 
  14. </Grid> 
  15. </UserControl> 
MainPage.xaml.cs源代码
 
  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Linq; 
  4. using System.Net; 
  5. using System.Windows; 
  6. using System.Windows.Controls; 
  7. using System.Windows.Documents; 
  8. using System.Windows.Input; 
  9. using System.Windows.Media; 
  10. using System.Windows.Media.Animation; 
  11. using System.Windows.Shapes; 
  12. using System.Threading; 
  13. using SLWebService.ServiceReference1; 
  14. namespace SLWebService 
  15. public partial class MainPage : UserControl 
  16. public MainPage() 
  17. InitializeComponent(); 
  18. //初始化的时候就执行 
  19. GetMoreList(); 
  20. GetList(); 
  21. List<info> infoMoreList = new List<info>(); 
  22. List<info> infoList = new List<info>(); 
  23. WserviceSoapClient MoreClient = new WserviceSoapClient(); 
  24. WserviceSoapClient LessClient = new WserviceSoapClient(); 
  25. private void button1_Click(object sender, RoutedEventArgs e) 
  26. this.listBox1.ItemsSource = infoMoreList; 
  27. this.listBox1.DisplayMemberPath = "Infostr"
  28.  
  29. private void button2_Click(object sender, RoutedEventArgs e) 
  30. this.listBox2.ItemsSource = infoList; 
  31. this.listBox2.DisplayMemberPath = "Infostr"
  32.  
  33. #region 获取到错误的数据条数 条数是N*N 
  34. /// <summary> 
  35. /// 获取错误的多条数据的方法 
  36. /// </summary> 
  37. public void GetMoreList() 
  38. //清除infoMoreList数据集,然后循环访问WebService方法 
  39. infoMoreList.Clear(); 
  40. //错误的循环获取WebBSer 
  41. for (int i = 1; i < 6; i++) 
  42. MoreClient.GetDataAsync(i); 
  43. MoreClient.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(wClient_GetDataCompleted); 
  44. void wClient_GetDataCompleted(object sender, GetDataCompletedEventArgs e) 
  45. info inf = new info() 
  46. Id=1, Infostr=e.Result 
  47. }; 
  48. infoMoreList.Add(inf); 
  49. #endregion 
  50.  
  51. #region 获取正确的数据条数 
  52. /// <summary> 
  53. /// 获取正确数据的方法 
  54. /// </summary> 
  55. public void GetList() 
  56. //清除infoList数据集,然后循环访问WebService方法 
  57. infoList.Clear(); 
  58. for (int i = 1; i < 6; i++) 
  59. LessClient.GetDataAsync(i); 
  60. LessClient.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(wClient_LessGetDataCompleted); 
  61.  
  62. void wClient_LessGetDataCompleted(object sender, GetDataCompletedEventArgs e) 
  63. info inf = new info() 
  64. Id=1, Infostr=e.Result 
  65. }; 
  66. infoList.Add(inf); 
  67. #endregion 
  68.  
  69. /// <summary> 
  70. /// 信息类 属性Id为ID值,属性Infostr为信息类的字符值 
  71. /// </summary> 
  72. public class info 
  73. int id; 
  74. string infostr; 
  75.  
  76. public int Id 
  77. get { return id; } 
  78. set { id = value; } 
  79.  
  80. public string Infostr 
  81. get { return infostr; } 
  82. set { infostr = value; } 

         本实例采用VS2010+Silverlight 4.0编写,点击 SLWebService.rar 下载源代码。