Web Service的一些经验和技巧总结

本文详细介绍使用 Silverlight 调用 WebService 的步骤及技巧,包括创建 WebService、客户端类设计、异步调用控制及松耦合实现等关键环节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

      先看整体项目布局(如下图所示),有个大体的了解。Jasen.SilverlightService为silverlight项目,Jasen.SilverlightService.Core为实现松耦合的类库,Jasen.SilverlightService.Web为Web服务发布网站。本文将讲解web服务的注意事项以及使用技巧。这是本人在开发中的一些经验以及总结,本来是需要通过WEB服务获取相关的2个数据,然后进行算法处理的(采用职责链设计模式设计路径算法),这里仅仅是大体框架而已,希望本文能够对读者有一定的帮助。

 

(一)创建Web Service服务

 

        以前总喜欢使用接口来进行编码,但是这里得注意了,Web服务方法的返回类型是不允许使用接口的,如不能使用IList<T>类型等等(经验之谈而已,免得到时候代码全部需要修改)而且该类型T必须是可序列化的,还有一点就是类型如果有参数的构造函数,必须显示实现无参构造函数。

 

        按照下列顺序创建web服务(可以发现属性的get;set;所产生的影响):

(1) 先在Jasen.SilverlightService.Web里定义一个实体类,我将SmallTitle(string)、IsSucceed(bool)设置为只读的类型并且赋初始值,其他的设置为自动属性{get;set;}

ExpandedBlockStart.gif 代码
  ///   <summary>
    
///  
    
///   </summary>
     public   class  ServerInfo
    {
        
private   bool  _isSucceed  =   true ;
        
private   string  _smallTitle  =   " small title " ;

        
///   <summary>
        
///  
        
///   </summary>
          public string  SmallTitle
        {
            
get

            {
                
return  _smallTitle;
            }
        }


        
///   <summary>
        
///  
        
///   </summary>
         public   string  Title
        {
            
get ;
            
set ;
        }

        
///   <summary>
        
///  
        
///   </summary>
         public   string  Content
        {
            
get ;
            
set ;
        }

        
///   <summary>
        
///  
        
///   </summary>
         public   bool  IsSucceed
        {
            
get
            {
                
return  _isSucceed;
            }
        }

        
///   <summary>
        
///  
        
///   </summary>
         public   bool  IsPublished
        {
            
get ;
            
set ;
        }
    }

 

 

(2) 然后我们在Jasen.SilverlightService.Web里面创建一个web服务(其实在这里创建是不太合理的,主要是为了简便),命名为InfoService,如下图所示意。

 

 

(3)在InfoService.cs编写相应的web服务方法,代码如下(为什么定义2个类似的方法,主要是针对后面异步操作的问题,2次异步操作如果同时操作无法确定哪次先完成,哪次后完成。完全是靠技巧,想到了就很简单,没想到就感觉非常复杂、无法控制):

 5          [WebMethod]
 6           public  List < ServerInfo >  GetFirstInfos()
 7          {
 8              List < ServerInfo >  infos  =   new  List < ServerInfo > ()
 9              {
10               new  ServerInfo{ Title = " Title1 " , Content = " Jasen " ,IsPublished = true   },
11               new  ServerInfo{ Title = " Title2 " , Content = " Jasen " ,IsPublished = true  },
12               new  ServerInfo{ Title = " Title3 " , Content = " Jasen "  },
13               new  ServerInfo{ Title = " Title4 " , Content = " Jasen "  },
14              };
15 
16               return  infos;
17          }
18 
23          [WebMethod]
24           public  List < ServerInfo >  GetSecondInfos()
25          {
26              List < ServerInfo >  infos  =   new  List < ServerInfo > ()
27              {
28               new  ServerInfo{ Title = " Title1 " , Content = " Jasen2 " ,IsPublished = true  },
29               new  ServerInfo{ Title = " Title2 " , Content = " Jasen2 "  },
30               new  ServerInfo{ Title = " Title3 " , Content = " Jasen2 "  },
31               new  ServerInfo{ Title = " Title4 " , Content = " Jasen2 "  },
32              };
33 
34               return  infos;
35          }  

 

 

(4)右键单击InfoService.asmx,在弹出的快捷菜单中单击“在浏览器中查看”,弹出如下窗口:

 

(5)单击上面中的任一的一个方法,弹出如下界面:

 

(6)单击调用,我们将发现如下情况,SmallTitle(string)、IsSucceed(bool)为只读类型(只有get方法)没有显示相关信息,只有同时有get,set方法的属性才会有相关的信息显示(这里需要注意了)。如下图绿色标识框中所示:

 

(二)创建一个ClientInfo类(主要是针对ServerInfo类,与之相区别),然后添加相应的web service引用到Silverlight项目中

 

ExpandedBlockStart.gif 代码
///   <summary>
    
///  
    
///   </summary>
     public   class  ClientInfo
    {
        
///   <summary>
        
///  
        
///   </summary>
         public   string  Title
        {
            
get ;
            
set ;
        }

        
///   <summary>
        
///  
        
///   </summary>
         public   string  Content
        {
            
get ;
            
set ;
        }

        
///   <summary>
        
///  
        
///   </summary>
         public   bool  IsPublished
        {
            
get ;
            
set ;
        }
    }

 

 

 

(三)页面中使用Web服务(如何控制二次异步操作的先后顺序,想到了就很简单)

 

 1  public   partial   class  MainPage : UserControl
 2      {
 3          InfoServiceSoapClient client;
 4 
 5           public  MainPage()
 6          {
 7              InitializeComponent();
 8              InitializeService();
 9          }
10 
11           ///   <summary>
12           ///  
13           ///   </summary>
14           private  ObservableCollection < ServerInfo >  FirstInfos
15          {
16               get ;
17               set ;
18          }
19 
20           ///   <summary>
21           ///  
22           ///   </summary>
23           private  ObservableCollection < ServerInfo >  SecondInfos 
24          {
25               get
26               set ;
27          }
28 
29           ///   <summary>
30           ///  
31           ///   </summary>
32           private   void  InitializeService()
33          {
34              client  =   new  InfoServiceSoapClient();
35              client.GetFirstInfosCompleted  +=   new  EventHandler < GetFirstInfosCompletedEventArgs > (client_GetFirstInfosCompleted);
36              client.GetFirstInfosAsync();
37          }
38 
39           ///   <summary>
40           ///  
41           ///   </summary>
42           ///   <param name="sender"></param>
43           ///   <param name="e"></param>
44           void  client_GetFirstInfosCompleted( object  sender, GetFirstInfosCompletedEventArgs e)
45          {
46               if  (e.Result  !=   null   &&  e.Error  ==   null )
47              {
48                   this .FirstInfos  =  e.Result;
49                  client.GetSecondInfosCompleted  +=   new  EventHandler < GetSecondInfosCompletedEventArgs > (client_GetSecondInfosCompleted);
50                  client.GetSecondInfosAsync();
51              }
52          }
53 
54           ///   <summary>
55           ///  
56           ///   </summary>
57           ///   <param name="sender"></param>
58           ///   <param name="e"></param>
59           void  client_GetSecondInfosCompleted( object  sender, GetSecondInfosCompletedEventArgs e)
60          {
61               if  (e.Result  !=   null   &&  e.Error  ==   null )
62              {
63                   this .SecondInfos  =  e.Result;
64                   if  ( this .FirstInfos  !=   null )
65                  {
66                      ClientInfoHandler < ServerInfo >  handler  =   new  ClientInfoHandler < ServerInfo > ();
67                      List < ClientInfo >  clientInfos  =  handler.Convert( this .FirstInfos,  this .SecondInfos);
68 
69                      dataGrid.ItemsSource  =  clientInfos;
70                  }
71              }
72          }
73      }

 

 

(1)我们发现如下代码被标成红色

          void client_GetFirstInfosCompleted(object sender, GetFirstInfosCompletedEventArgs e)
         {
             if (e.Result != null && e.Error == null)
             {

                this.FirstInfos = e.Result;
                client.GetSecondInfosCompleted += new EventHandler<GetSecondInfosCompletedEventArgs>(client_GetSecondInfosCompleted);                

                client.GetSecondInfosAsync();            

              }
         }
在这里设置this.FirstInfos = e.Result;  ,然后再次异步调用第二个方法, client.GetSecondInfosAsync();  --->这样我们就能够控制获取数据的时间先后顺序。

 

(2)在第二次异步调用的回调方法中,我们将处理从web服务返回的数据。

      void client_GetSecondInfosCompleted(object sender, GetSecondInfosCompletedEventArgs e)
      {

          handler.Convert(this.FirstInfos, this.SecondInfos);//在这里处理相应从web服务返回的数据。类型为ObservableCollection<ServerInfo>

      }


(3)
GetSecondInfosCompletedEventArgs的Result属性如下:

  public  System.Collections.ObjectModel.ObservableCollection < Jasen.SilverlightService.InfoService.ServerInfo >  Result {
            
get  {
                
base .RaiseExceptionIfNecessary();
                
return  ((System.Collections.ObjectModel.ObservableCollection < Jasen.SilverlightService.InfoService.ServerInfo > )( this .results[ 0 ]));
            }
        }

 

 

(四)如何解除耦合(采用反射将ServerInfo转换为ClientInfo:松耦合)

 

     返回类型为System.Collections.ObjectModel.ObservableCollection<Jasen.SilverlightService.InfoService.ServerInfo>,为了解除耦合,定义一个ClientInfoHandler<T>泛型类来处理需要转换的数据。

      public List<ClientInfo> Convert(ObservableCollection<T> firstCollection,  ObservableCollection<T> secondCollection)
      {

      }
在这一步里,
我们主要是通过反射来获取属性的值 object result = type.InvokeMember(propertyName, invokeAttr, null, item, args);更多信息请参考MSDN。

 

这样我们就将ServerInfo转换为ClientInfo了,并且解除了耦合关系,实现了松耦合。当服务端(特别是数据库字段)变了之后,亦或者是类名都变了的时候,我们只需要对属性名称进行相应的修改即可。如下述代码所示:

  1  namespace  Jasen.SilverlightService.Core
  2  {
  3       public   class  ClientInfoHandler < T >
  4      {
  5           ///   <summary>
  6           ///  
  7           ///   </summary>
  8           ///   <param name="firstCollection"></param>
  9           ///   <param name="secondCollection"></param>
 10           ///   <returns></returns>
 11           public  List < ClientInfo >  Convert(ObservableCollection < T >  firstCollection,
 12              ObservableCollection < T >  secondCollection)
 13          {
 14               if  (firstCollection  ==   null   ||  secondCollection  ==   null   ||
 15                  firstCollection.Count  ==   0   ||  secondCollection.Count  ==   0 )
 16              {
 17                   return   null ;
 18              }
 19 
 20              List < ClientInfo >  firstList  =   new  List < ClientInfo > ();
 21              List < ClientInfo >  secondList  =   new  List < ClientInfo > ();
 22 
 23               foreach  (T item  in  firstCollection)
 24              {
 25                   // 反射获取属性值
 26                  ClientInfo info  =  ReflectItem(item);
 27                   if  (info  !=   null )
 28                  {
 29                      firstList.Add(info);
 30                  }
 31              }
 32 
 33               foreach  (T item  in  secondCollection)
 34              {
 35                   // 反射获取属性值
 36                  ClientInfo info  =  ReflectItem(item);
 37                   if  (info  !=   null )
 38                  {
 39                      secondList.Add(info);
 40                  }
 41              }
 42 
 43 
 44               return  ConvertList(firstList,secondList);
 45          }
 46 
 47           ///   <summary>
 48           ///  本来这里向写个算法什么的,还是算了,就相当于对2个数据进行操作就可以了
 49           ///   </summary>
 50           ///   <param name="firstList"></param>
 51           ///   <param name="secondList"></param>
 52           ///   <returns></returns>
 53           private  List < ClientInfo >  ConvertList(List < ClientInfo >  firstList, List < ClientInfo >  secondList)
 54          {
 55              if (firstList == null   ||  secondList == null || firstList.Count == 0 || secondList.Count == 0 )
 56             {
 57                  return   null ;
 58             }
 59 
 60              foreach  (ClientInfo item  in  secondList)
 61             {
 62                 firstList.Add(item);
 63             }
 64 
 65              return  firstList;
 66          }
 67 
 68           ///   <summary>
 69           ///  
 70           ///   </summary>
 71           ///   <param name="item"></param>
 72           ///   <returns></returns>
 73           private  ClientInfo ReflectItem( object  item)
 74          {
 75              ClientInfo info  =   new  ClientInfo();
 76              BindingFlags flags  =  BindingFlags.Public  |  BindingFlags.Instance 
 77                   |  BindingFlags.GetProperty;
 78            
 79              info.Content  =  GetPropertyValue(item,  " Content " , flags ,  null );
 80              info.Title  =  GetPropertyValue(item,  " Title " , flags,  null );
 81               if  ( string .Equals(GetPropertyValue(item,  " IsPublished " , flags,  null ),
 82                   " TRUE " , StringComparison.InvariantCultureIgnoreCase))
 83              {
 84                  info.IsPublished  =   true ;
 85              }
 86               else  
 87              {
 88                  info.IsPublished  =   false ;
 89              }
 90 
 91               return  info;
 92          }
 93 
 94           ///   <summary>
 95           ///  
 96           ///   </summary>
 97           ///   <param name="item"></param>
 98           ///   <param name="propertyName"></param>
 99           ///   <param name="invokeAttr"></param>
100           ///   <param name="args"></param>
101           ///   <returns></returns>
102           private   static   string  GetPropertyValue( object  item,  string  propertyName,
103              BindingFlags invokeAttr,  object [] args)
104          {
105              Type type  =  item.GetType();
106               string  value  =   "" ;
107 
108               try
109              {
110                   object  result  =  type.InvokeMember(propertyName, invokeAttr,
111                       null , item, args);
112 
113                   if  (result  !=   null )
114                  {
115                      value  =  result.ToString().Trim();
116                  }
117              }
118               catch  (MissingMethodException ex)
119              { 
120                 
121              }
122 
123               return  value;
124          }
125      }
126  }

  

 如果我们将 public List<ClientInfo> Convert(ObservableCollection<T> firstCollection,  ObservableCollection<T> secondCollection){}
改为public List<ClientInfo> Convert(List<ServerInfo> firstCollection,  List<ServerInfo> secondCollection){}

那么耦合太紧了,服务端一修改,处理类ClientInfoHandler就得改很多。采用范型和反射来操作的话,我们仅仅需要修改的是属性名称而已。

 

当然,你也可以同时将2个数据组装在一个类中,然后在一个Web服务方法中返回该类。界面显示如下(本来我的是算法路径图,哈哈)

 

(五)另附一种传递参数的方式(通过事件和委托)

 

 (1)我们继续添加一个silverlight类库以及一个App应用程序,如下所示:

 

(2)先看InfoProxy代理类,代理Web服务的处理,以及传递给UI。

 

 1       public   delegate   void  RouteEventHandler( object  sender, RouteEventArgs < ServerInfo >  args);
 2 
 3       public   class  InfoProxy
 4      {
 5 
 6           ///   <summary>
 7           ///  
 8           ///   </summary>
 9           public   event  RouteEventHandler OnRetrieve;
10 
11           ///   <summary>
12           ///  
13           ///   </summary>
14           public  InfoProxy()
15          {
16 
17          }
18 
19           ///   <summary>
20           ///  
21           ///   </summary>
22           public   void  HandlerData() 
23          {
24              InfoServiceSoapClient client  =   new  InfoServiceSoapClient();
25              client.GetFirstInfosCompleted  +=   new  EventHandler < GetFirstInfosCompletedEventArgs > (client_GetFirstInfosCompleted);
26              client.GetFirstInfosAsync();
27          }
28 
29           void  client_GetFirstInfosCompleted( object  sender, GetFirstInfosCompletedEventArgs e)
30          {
31               if  (e.Result  !=   null && e.Error == null )
32              {
33                  List < ServerInfo >  items  =   new  List < ServerInfo > ();
34                   foreach  (var item  in  e.Result)
35                  {
36                       if  (item  !=   null )
37                      {
38                          items.Add( new  ServerInfo()
39                          {
40                              Content  =  item.Content,
41                              Title  =  item.Title
42                          });
43                      }
44                  }
45                   //  这里是可以对ServerInfo进行处理的,进行算法处理----------处理后再传给UI
46                   // 现在这里是没有进行处理,直接传给UI的---------控制
47                   RouteEventArgs < ServerInfo >  args  =   new  RouteEventArgs < ServerInfo > ();
48                  args.Result  =  items.ToArray();
49                  args.Error  =  e.Error;
50                   this .OnRetrieve(sender, args);
51              }
52          }
53      }

 

 

 在  void client_GetFirstInfosCompleted(object sender, GetFirstInfosCompletedEventArgs e){}方法里,将触发事件this.OnRetrieve(sender, args); 。我们将数据保存在参数类RouteEventArgs<T> 中,

 1    public   class  RouteEventArgs < T >  : EventArgs
 2      {
 3           private  T[] _result;
 4 
 5           ///   <summary>
 6           ///  
 7           ///   </summary>
 8           public  T[] Result
 9          {
10               get
11              {
12                   return  _result;
13              }
14               set
15              {
16                  _result  =  value;
17              }
18          }
19 
20           public  Exception Error
21          {
22               get ;
23               set ;
24          }
25      }

 

 

(3)在UI层,我们通过如下代码对WEB服务进行调用(通过InfoProxy类),如下

 

 1     public  MainPage()
 2          {
 3              InitializeComponent();
 4               InfoProxy proxy  =   new  InfoProxy();
 5              proxy.OnRetrieve  +=   new  RouteEventHandler(proxy_OnRetrieve);
 6              proxy.HandlerData();
 7          }
 8 
 9           void  proxy_OnRetrieve( object  sender, RouteEventArgs < Core.InfoService.ServerInfo >  args)
10          {
11               if  (args.Result  !=   null && args.Error == null )
12              {
13                  dataGrid.ItemsSource   =  args.Result;
14              }
15          }

 

 

先将事件绑定,然后再调用proxy.HandlerData();。避免事件为NULL。

 

(4)记得加上访问策略文件crossdomain.xml

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
  <allow-access-from domain="*" />
  <allow-http-request-headers-from domain="*" headers="*"/>
</cross-domain-policy>

 

显示如下

 

希望本文对各位有所帮助,源代码下载地址:Web Services相关的一些总结

 

转载于:https://www.cnblogs.com/jasenkin/archive/2010/12/26/silverlight_webservice.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值