• WCF(二) Contract


    上篇只是介绍了WCF的概述。具体的设置全是使用默认,这当然不可能满足我们开发的需要。如果仔细理一理的话,你会发现WCF里面的设置其实不算多的(与SharePoint比较的话)。从这篇开始,我们一点一点来展开学习。这次先提最最常用的Contract。

    Contract有人翻译为:协定,契约。

    WCF中有四种contract: 分别是:1.Service Contract. 2.Data Contract. 3. Fault Contract. 4.Message Contract.

    还拿上篇中的例子(其实就是有Visual Studio2010替我们默认生成的代码了)说事:

    1.Service Contract共分为两个部分:定义部分和实现部分。

     1     [ServiceContract]
     2     public interface IService1
     3     {
     4         [OperationContract]
     5         string GetData(int value);
     6 
     7         [OperationContract]
     8         CompositeType GetDataUsingDataContract(CompositeType composite);
     9       
    10     }

    这里IService就是一个service contract的定义部分,指定了哪些函数(Operation)向外公开(即:可供Client调用)。被[OperationContract]修饰的函数可以被客户端(Client)调用。
    [OperationContent]是Attribute。关于Attribute不太明白的,请参考:《别弄混了C#.的几个小概念Attribute,property,field

     1     public class Service1 : IService1
     2     {
     3         public string GetData(int value)
     4         {
     5             return string.Format("You entered: {0}", value);
     6         }
     7 
     8         public CompositeType GetDataUsingDataContract(CompositeType composite)
     9         {
    10             if (composite == null)
    11             {
    12                 throw new ArgumentNullException("composite");
    13             }
    14             if (composite.BoolValue)
    15             {
    16                 composite.StringValue += "Suffix";
    17             }
    18             return composite;
    19         }
    20     }

    Service1实现了IService接口,是Service Contract 的实现部分。VS自动生成的代码太简单了,不解释了。这里为了尽可能简单地说明问题。具体项目中,你可能需要连接数据库增、删、改、查数据,或对数据按n多复杂的业务规则进行数据处理以后,返回给client,等。
    [ServiceContract] Attribute 可以有以下Property 的:

    CallbackContract 设置callback的类型:Duplicate指Service Host和Client之间进行双向通信
    ConfigurationName 指定配置文件中某个configuration的名字
    HasProtectionLevel 标示是否可以处理安全消息
    Name 给contract指定一个名字,在client端可见的名字,默认就是接口名字
    Namespace 给消息指定一个命名空间
    ProtectionLevel  
    SessionMode 指允许,还是不允许,还是强制session

    [OperationContract] Attribute 可以有以下Property 的:

    Action 对请求设置WS-Addressing 的action
    AsynchPattern 异步模式
    HasProtectionLevel 消息是否加密,签名
    IsInitiating 表明该函数被调用开始时是否要在server上面初始化一个session
    IsOneWay 表明函数被client调用以后,client是否会等待函数返回
    IsTerminating 表明该函数被调用结束时是否要在server上面关闭session
    Name 设置函数的名字,在client端可见的名字,默认就是函数名字
    ProtectionLevel  
    ReplyAction 设置函数返回消息的SOAP action

    1.1 我们修改一下Service的默认命名空间,使他更make scene(有意义).

    打开上篇中的解决方案WcfFirstDemo.sln

    右键WebHost项目下面的文件:Service.svc,如下图:

    点击连接如图:

    得到如图效果:

    默认Namespace是http://tempuri.org/

    微软官方建议:修改Service的Namespace,使其包含:公司域名+项目名+版本号(如:日期表示版本号)

    修改项目:WcfFirstDemoServiceLib下面的IService.cs代码如下:

     1     [ServiceContract(Namespace="http://wwww.cnblogs.com/WCF/2012/07/28")]
     2     public interface IService1
     3     {
     4         [OperationContract]
     5         string GetData(int value);
     6 
     7         [OperationContract]
     8         CompositeType GetDataUsingDataContract(CompositeType composite);
     9       
    10     }

    右键项目WcfFirstDemoServiceLib 选择重新编译,成功以后,重新用浏览器打开service.svc,得到如下图:

    此时已经改变了Service默认的Namespace了,client端需要更新一下,否则运行client端是会报异常的.操作如下图:

    1.2修改Service的Name.默认情况下定义service的接口部分(如本例:IService)的名字就是Service的名字.但有时需要让client看到的service的名字跟server端看到的的service名字不一样.

    我们先看一下WCFClient项目下面的app.config

    修改WcfFirstDemoServiceLib项目下的IService.cs文件

     1     [ServiceContract(Namespace="http://wwww.cnblogs.com/WCF/2012/07/28",Name="DemoService")]
     2     public interface IService1
     3     {
     4         [OperationContract(Name="GetAge")]
     5         string GetData(int value);
     6 
     7         [OperationContract]
     8         CompositeType GetDataUsingDataContract(CompositeType composite);
     9       
    10     }

    重新编译WcfFirstDemoServiceLib项目.更新client端对service的引用.此时你会发现client端app.config文件前后发生了变化:

    此时WCFClient所生成的代理类的名字也会变化,你需要修改WCFClient

    1    DemoService proxy = null;
    1         private void Form1_Load(object sender, EventArgs e)
    2         {
    3             proxy = new DemoServiceClient("BasicHttpBinding_DemoService");
    4 
    5         }
    1         private void btnGetData_Click(object sender, EventArgs e)
    2         {
    3             this.tbOutputBox.Text = proxy.GetAge(Convert.ToInt32(this.tbInputbox.Text));
    4         }

    :上面代码中DemoService 对应server端IService接口;DemoServiceClient对应server端的Service类.

    当client端的app.config文件中只包含一个endpoint时,可以直接用proxy=new DemoServiceClient()传空参数,当然也可以传这个endpoint的name进去;但是当app.config包含多个endpoint时必须把endpoint的name传进去才能new出proxy对象.

    2.DataContract.

    WCF的Server和client之间利用特定格式的Message(消息)进行通信的。但是我们使用的高级语言:不论在Server端还是在client端,我们处理的业务数据都被封装成了对象。所以想把server端的对象传送到client(或相反方向)时,我们必须有能力把这些对象转换成特定格式的message,到另一端接收到message后再把它转回成对象。C#的基础类型(如int,string,float,bool等)可以做到这一点。因为一旦确定了Server端或client所用的编程语言,就可以确定这些基础类型的内存占用情况(例如:一个Server端定义的int变量在C#中占用多大内存空间是已知的,那么client端即便使用的是其他语言也完全可以计算出该变量的内存占用情况)。可是我们自己定义的类型可是五花八门了(比如:server端定义的Person类new出的object到底占用多大内存空间,就算Server端与client端使用同一种语言,Client端是不知道的Person类的对象的内存占用情况的。)

    遇到这种请款下,我们怎么办呢?这时就轮到[DataContract]露面了。

    遇到这种请款下,我们怎么办呢?这时就轮到[DataContract]露面了。

    ServiceContract做的工作是指定service向client提供了哪些函数可供调用。DataContract做的工作就是指定在Server端与client端之间可以传送的数据。[DataContract]的作用就是指定当需要传送某个类(如:Person类)的对象时,将该对象转化成为XML.接受方接到XML以后,再按同样的方式还原成对象。

    [DataContract]Attribute 标在class定义上面一行。[DataMember]Attribute标在Property定义上面一行,field不需要Attribute修饰。

     1     [DataContract]
     2     public class CompositeType
     3     {
     4         bool boolValue = true;
     5         string stringValue = "Hello ";
     6 
     7         [DataMember]
     8         public bool BoolValue
     9         {
    10             get { return boolValue; }
    11             set { boolValue = value; }
    12         }
    13 
    14         [DataMember]
    15         public string StringValue
    16         {
    17             get { return stringValue; }
    18             set { stringValue = value; }
    19         }
    20     }

    [DataContract]Attribute 可以像[ServiceContract]一样设置Name和Namespace.
    [DataMember] Attribute 可以有以下属性:

    EmitDefaultValue 设置一个默认值
    IsRequired 进行序列化/反序列化时该值一定不可为空值
    Name Property的名字
    Order 设置进行序列化/反序列化的顺序

     2.1修改DataContract的默认namespace , 

     1    [DataContract(Namespace = "http://wwww.cnblogs.com/WCF/2012/07/28", Name = "CompositeTypeDemo")]
     2     public class CompositeType
     3     {
     4         bool boolValue = true;
     5         string stringValue = "Hello ";
     6 
     7         [DataMember(Name="GetBool")]
     8         public bool BoolValue
     9         {
    10             get { return boolValue; }
    11             set { boolValue = value; }
    12         }
    13 
    14         [DataMember(Name="GetString")]
    15         public string StringValue
    16         {
    17             get { return stringValue; }
    18             set { stringValue = value; }
    19         }
    20     }

    这样在client端看到的类(class)名,函数名与server看到的就不相同.

     3.Fault Contract.

    在WCF中处理异常(Exception)的方法有些特殊.我们不能单从server处理exception,需要进一步将Exception从server传送到client. 在后面我们再单独讨论WCF的Exception处理.

    4. Message Contract.

    Message Contract与Data Contract都是作用在传送的对象(object)上面.

    不同的是:

    datacontract是将object序列化化为xml. 实现object的各个property与xml 文本中各个node(节点)的对应);

    messagecontract将对象组装成message(指定Message的Header,body).实现的是object各个property与消息的各个元素的对应.

    具体的深层区别于联系,以及使用场景,我还不懂,希望有朋友对着块比较懂的,可以交流一下.如果后面等我弄懂了的话,我再专门写博文交流.

  • 相关阅读:
    MySQL5.7修改默认密码、随机密码
    Java基础知识_毕向东_Java基础视频教程笔记(26 反射)
    Java基础知识_毕向东_Java基础视频教程笔记(22-25 GUI 网络编程 正则)
    Java基础知识_毕向东_Java基础视频教程笔记(19-21 IO流)
    Java基础知识_毕向东_Java基础视频教程笔记(14-18集合框架)
    Java基础知识_毕向东_Java基础视频教程笔记(13 字符)
    Java基础知识_毕向东_Java基础视频教程笔记(11-12 多线程)
    JIT和AOT编译详解
    PAT 说反话
    PAT 程序运行时间
  • 原文地址:https://www.cnblogs.com/marksun/p/2612662.html
Copyright © 2020-2023  润新知