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


          先看整体项目布局(如下图所示),有个大体的了解。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;}

    代码
     /// <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项目中

    代码
    /// <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相关的一些总结

  • 相关阅读:
    常用的STL
    CString,string,char数组的转换
    linux知识
    十一种通用滤波算法(转)
    修复被勒索病毒cl0p损坏的svn代码
    android shell 转发代理shell示例
    3proxy配置
    windbg调试写dmp,随机名字
    nexus6p刷机注意
    mysql语句学习
  • 原文地址:https://www.cnblogs.com/jasenkin/p/silverlight_webservice.html
Copyright © 2020-2023  润新知