• [转] 传说中的WCF(2):服务协定的那些事儿


    上一篇文章中,我们抛出了N个问题:WCF到底难不难学?复杂吗?如果复杂,可以化繁为简吗?

    其实,这些问题的答案全取决于你的心态,都说“态度决定一切”,这句话,不知道各位信不信,反正我是信了。首先,敢于挑战自我,乐于接受新事物的人,就不会觉得有啥难学的,“世上有难事,只怕有心人”;再者,WCF当然复杂了,整个.NET框架都复杂,但不难学,因为.NET有一个先天性优点——集成性和统一性严重地好,这也是我乐于研究.NET的主要原因之一,复杂但不混乱。一个统一的国家总比一个四分五裂的国家要强大;第三,任何东西都可以化繁为简,关键是你持什么样的心态。编程最高境界就是将程序和自然哲学等多种学术融为一体。

    今天聊聊服务协定,这个概念,如果你只停留在字面上去理解,你会发现灰常抽象。有两家公司经过七天七夜的谈判,终于达成基本一致的意见,于是,就签下了合作协议。根据合作协议要求,两家公司在ABCD项目上互相公开一定程度的资料,以便更好地合作。各位想一想,这个合作协议,像不像我们这里说的服务协定?是啊,服务协定其实没啥了不起的,刚才签下合作协议的两家公司分别叫“服务器端”和“客户端”。

    服务协定告诉客户端,哪些方法你可以调用,哪些数据类型你可使用,至于公不公开接口让你调用,就完全取决于服务器端如何定义服务协定了。

    比如下面这个协定:

    1. [ServiceContract]  
    2. public interface IServiceA  
    3. {  
    4.     [OperationContract]  
    5.     int AddInt(int a, int b);  
    6.   
    7.     [OperationContract]  
    8.     double AddDouble(double a, double b);  
    9.   
    10.     float AddFloat(float a, float b);  
    11. }  


    实现该协定:

    1. public class MyService : IServiceA  
    2. {  
    3.     public int AddInt(int a, int b)  
    4.     {  
    5.         return a + b;  
    6.     }  
    7.   
    8.     public double AddDouble(double a, double b)  
    9.     {  
    10.         return a + b;  
    11.     }  
    12.   
    13.     public float AddFloat(float a, float b)  
    14.     {  
    15.         return a + b;  
    16.     }  
    17. }  


    大家可以猜一下,在客户端中生成的代码中,哪你能看到哪些方法,哪些方法将看不到?上面的服务协定中,我们定义了三个方法,其中前两个是带了操作协定OperationContractAttribute的,而AddFloat方法是没有用标注为协定的。那么,生成的客户端代码会如何呢?

    是不是少了一个方法呢?对啊,就是少了AddFloat,还记得吗?我们上面的代码中,AddFloat方法是没有标注为操作协定的。

    好的,现在我们为AddFloat加上操作协定,如下所示。

    1. [ServiceContract]  
    2. public interface IServiceA  
    3. {  
    4.     [OperationContract]  
    5.     int AddInt(int a, int b);  
    6.   
    7.     [OperationContract]  
    8.     double AddDouble(double a, double b);  
    9.   
    10.     [OperationContract]  
    11.     float AddFloat(float a, float b);  
    12. }  


    这时候,看看在客户端能看到多少个方法。

    这回全到齐了,对吧。

    下面来看看服务的命名空间。

    ServiceContractAttribute有个属性Namespace,用于设置服务的命名空间,由于避免放到互联网中与其它服务冲突,命名空间必须是唯一的(其实就是XML命名空间),多数情况下,我们会使用公司主页的地址或个人网站地址,因为这些地址是唯一的。

    在不设置命名空间的时候,我们看看客户端代码默认生成的命名空间是什么。

    在“解决方案资源管理器”窗口上,点击“显示所有文件”,如下图所示。

    打开.wsdl文件。

    1. <wsdl:types>  
    2.   <xsd:schema targetNamespace="http://tempuri.org/Imports">  
    3.     <xsd:import schemaLocation="http://localhost:9000/service?xsd=xsd0" namespace="http://tempuri.org/" />  
    4.     <xsd:import schemaLocation="http://localhost:9000/service?xsd=xsd1" namespace="http://schemas.microsoft.com/2003/10/Serialization/" />  
    5.   </xsd:schema>  
    6. </wsdl:types>  


    我们看到,默认的命名空间是http://tempuri.org/,然后,回到服务器端的代码,我们显式设置一个命名空间,看看生成的客户端代码又将如何。

    1. [ServiceContract(Namespace = "http://MyApp.net")]  
    2. public interface IServiceA  
    3. {  
    4.     [OperationContract]  
    5.     int AddInt(int a, int b);  
    6.   
    7.     [OperationContract]  
    8.     double AddDouble(double a, double b);  
    9.   
    10.     [OperationContract]  
    11.     float AddFloat(float a, float b);  
    12. }  


    好了,现在再看看WSDL文件会变成啥样。

    我们发现,现在的WSDL文件和刚才不一样了,上面出现了我们自定义的命名空间。

    我们也许还会问,命名空间一定要用http://的方式吗?我用其它字符串行吗?不必问,试一下就知道了。

    1. [ServiceContract(Namespace = "FuckingDog")]  
    2. public interface IServiceA  
    3. {  
    4.        .............  


    再看看这次生成的客户端代码中,WSDL中是如何描述。

    好了,结论出来了。

    ServiceContractAttribute类还有一个属性Name,那么设置了该属性会发生什么?不急,我们先来看看不设置Name的情况下是如何。

    我们看到,默认情况下,生成的WSDL直接使用服务协定的名字,即IServiceA。那么,如果我们在定义服务协定时修改了Name属性,那会如何?

    1. [ServiceContract(Namespace = "FuckingDog", Name = "HaHaHa")]  
    2. public interface IServiceA  
    3. {  
    4.       .......  


    看对比一下生成的WSDL文件。

    现在,就变成“HaHaHa”了,呵呵,这有啥用呢?哈,问你一句,如果你上网聊天的时候,不希望对方知道你的真实姓名时,你会咋办?嘿,弄个网名呗,就是了,为服务协定弄一下Name属性,就相当于为它取一个网名呗。

    还有哦,这个网名不仅仅服务协定可以取,操作协定也可以,来,看看。

    1. [ServiceContract(Namespace = "FuckingDog", Name = "HaHaHa")]  
    2. public interface IServiceA  
    3. {  
    4.     [OperationContract(Name = "OperatFirst")]  
    5.     int AddInt(int a, int b);  
    6.   
    7.     [OperationContract(Name = "OperatSecond")]  
    8.     double AddDouble(double a, double b);  
    9.   
    10.     [OperationContract(Name = "OperatThird")]  
    11.     float AddFloat(float a, float b);  
    12. }  


    你猜猜,这样改了以后,生成的客户端代码会啥样子?

    猜对了吗?这样一来啊,调用服务的人就不知道你姓甚名谁了。

    怎么样?WCF有趣不?本文的服务器端示例完整代码清单如下。

    1. using System;  
    2. using System.Collections.Generic;  
    3. using System.Linq;  
    4. using System.Text;  
    5. using System.ServiceModel;  
    6. using System.ServiceModel.Description;  
    7.   
    8. namespace Server  
    9. {  
    10.     [ServiceContract(Namespace = "FuckingDog", Name = "HaHaHa")]  
    11.     public interface IServiceA  
    12.     {  
    13.         [OperationContract(Name = "OperatFirst")]  
    14.         int AddInt(int a, int b);  
    15.   
    16.         [OperationContract(Name = "OperatSecond")]  
    17.         double AddDouble(double a, double b);  
    18.   
    19.         [OperationContract(Name = "OperatThird")]  
    20.         float AddFloat(float a, float b);  
    21.     }  
    22.   
    23.     public class MyService : IServiceA  
    24.     {  
    25.         public int AddInt(int a, int b)  
    26.         {  
    27.             return a + b;  
    28.         }  
    29.   
    30.         public double AddDouble(double a, double b)  
    31.         {  
    32.             return a + b;  
    33.         }  
    34.   
    35.         public float AddFloat(float a, float b)  
    36.         {  
    37.             return a + b;  
    38.         }  
    39.     }  
    40.   
    41.   
    42.     class Program  
    43.     {  
    44.         static void Main(string[] args)  
    45.         {  
    46.             using (ServiceHost host = new ServiceHost(typeof(MyService),new Uri("http://localhost:9000/service")))  
    47.             {  
    48.                 WSHttpBinding binding = new WSHttpBinding();  
    49.                 binding.Security.Mode = SecurityMode.None;  
    50.                 host.AddServiceEndpoint(typeof(IServiceA), binding, "contract1");  
    51.                 host.Description.Behaviors.Add(new ServiceMetadataBehavior() { HttpGetEnabled = true });  
    52.                 host.Opened += (sd, arg) => Console.WriteLine("服务已启动。");  
    53.                 try  
    54.                 {  
    55.                     host.Open();  
    56.                 }  
    57.                 catch (Exception ex)  
    58.                 {  
    59.                     Console.WriteLine(ex.Message);  
    60.                 }  
    61.                 Console.ReadKey();  
    62.                 host.Close();  
    63.             }  
    64.         }  
    65.     }  
    66. }  


     

    最后,说说WSDL的事儿,这个家伙我们了解一下就够了,为啥,我们不必自己动手写WSDL文档,甚至说,你看不懂也不影响编程,因为强大的Visual Studio在我们引用服务时,会为我们生成所需的代码,我们就像使用一般类一个使用就可以了。

    若想了解WSDL,看看这个,不错,挺简洁明了的。http://www.w3school.com.cn/wsdl/index.asp

  • 相关阅读:
    传统线程互斥和同步通信
    【计算机视觉】人脸表情识别技术
    【计算机视觉】人脸识别--人脸识别技术综述
    【计算机视觉】人脸识别--人脸识别技术综述
    【计算机视觉】人脸识别之人脸对齐(一)--定义及作用
    【计算机视觉】人脸识别之人脸对齐(一)--定义及作用
    【神经网络与深度学习】转-caffe安装吐血总结
    【神经网络与深度学习】转-caffe安装吐血总结
    【图像处理与医学图像处理】YUV与RGB格式转换速度几种方法对比
    【图像处理与医学图像处理】YUV与RGB格式转换速度几种方法对比
  • 原文地址:https://www.cnblogs.com/fan-yuan/p/3718189.html
Copyright © 2020-2023  润新知