• WCF 基础之契约(Contract)[转]


    1. WCF 基础之契约(Contract
    契约(Contract)是 WCF 的消息标准,告知客户端如何与服务器联系交互。契约是平台中立的,也就说我们可以使用其它平台(包括开发和系统平台)来调用服务。WCF 中包含 4 种契约,分别是用于定义服务操作(Operations)的 Service Contract,定义自定义数据结构的 Data Contract,定义错误异常的 *Fault Contract,以及直接控制消息格式的 Message Contract。它们算是WCF的核心之一,如果你要使用WCF,就需要了解他们。

    • Service contracts : 定义客户端可以使用哪些服务操作。
    • Data contracts : 定义服务传输的数据类型。WCF 定义了一些隐式数据契约,像 int、string 等,更多时候我们需要使用 DataContractAttribute 显式定义那些自定义数据结构的数据契约。
    • Fault contracts : 定义服务引发的错误信息,以及如何传递这些异常给客户端。
    • Message contracts : 允许我们直接操控服务消息内容和格式,可以是类型化或无类型的。

    2. 服务契约(Service Contract)
    一般情况下,我们用接口(Interface)来定义服务契约(Service Contract)。虽然我们也可以使用 Class,但使用接口的好处更明显一些。便于契约的继承,不同根的类型可以自由实现相同的契约。

    • 同一服务类型可以实现多个契约。
    • 和接口隔离原则相同,我们随时可以修改服务类型。
    • 便于制定版本升级策略,让新老版本的服务契约同时使用。

    WCF 使用特性 ServiceContractAttribute 标定服务契约,OperationContractAttribute 标定服务方法。

    ServiceContract public interface ICalculate { OperationContract double Add(double a, double b); }


    OperationContract 只能用于 Method,只有添加了此特性的方法才能被客户端调用。它甚至可以用来标注私有方法,这显然超出了面向对象的规则,而更多的是 SOA 的方式。SOA 只是分布式系统的架构体系,在架构体系内部我们依然采取面向对象的原则来编码,所以标注私有方法是不被推荐的,这也是使用接口作为服务契约的一个好处(接口中无法定义私有方法)。

    异步 Asynchronous
    在WCF中,如果在服务契约中建立了异步方法,那么客户端代理将同时存在异步和非异步版本。
    设置OperationContract的AsyncPattern:=True 即可以建立异步方法

    双向通讯 Duplex
    通过在服务契约中指定CallbackContract:=GetType(ICalculatorDuplexCallback)即可以指定回调接口。 在回调的时候,由于系统会确认执行过程。所以,为了避免死锁,一般加上(IsOneWay:=True)>关键字。

    Oneway
    在我们的程序中,有些服务是不需要确认是否到达到服务器的或者没有返回值的。这个时候我们可以设置IsOneWay:=True 这样,WCF便不会等到执行完才返回了。

    Session
    虽然在SOA中,提议每个服务请求都是独立的。但是,我们有时候需要保存一些数据,比如:用户ID。这个时候,我们可以把这个数据保存回话中。 WCF中,支持3种回话模式
    1. Pre-Call: 服务实例被释放,客户端抛出 FaultException,客户端代理对象无法继续使用。
    2. Pre-Session: 服务实例被释放,会话终止。客户端抛出 FaultException,客户端代理对象无法继续使用。
    3. Singleton: 服务实例依旧运行,会话终止。客户端抛出 FaultException,客户端代理对象无法继续使用。

    流 Stream
    在WCF中也支持流传输,这时候,有点类似打开TCP端口~。对于传输大量数据比较有效率,例如:上传文件。记得在使用的时候配置好最大消息的大小

    ServiceContract 的属性

    • ConfigurationName: 其设置信息在配置文件中的名称。
    • Name / Namespace:自定义该服务契约的名称和命名空间。建议设置服务契约的 Name 和 Namespace,这样生成的客户端的代理文件会使用自定义名称来命名相关代理类型,即便我们日后对服务器端的契约名称进行重构也不会影响到客户端。
    • SessionMode:设置服务契约的 Session 方式,包括 Allowe、NotAllowed、Required。SessionMode 需要相应的 Binding 支持,默认情况下会自动启用,另外我们还会和 ServiceBehaviorAttribute.InstanceContextMode 配合使用来管理服务对象的生命周期。
    • CallbackContract:设置 duplex 模式时的回调类型。
    • ProtectionLevel:指定消息保护方式,可以对消息进行加密和签名处理。
    • OperationContract 的属性
    • AsyncPattern:用于定义异步服务方法。
    • IsInitiating:指示服务方法能否启动一个 Session。
    • IsTerminating:指示服务方法调用完成是否结束 Session。

    3. 数据契约(Data Contract)
    数据契约(Data Contract)是用来标识用户自定义类型和序列化。
    DataContractAttribute、DataMemberAttribute 来标注自定义数据类型,这样我们就可以在服务方法中传递复杂的数据体了。使用之前,我们需要添加 System.Runtime.Serialization.dll 引用。由此我们可以看出其基本的开发模式,那就是使用 ServiceContract、OperationContract 执行运算,而使用 DataContract、DataMember 作为可序列化的数据载体。当然,我们也可以使用 "Serializable" 代替 "DataContract"。
    其实,数据契约主要是定义数据的格式(契约)。DataMember()是告诉序列化引擎要序列化的那个部分(关于序列化,注意一点,反序列化时可以访问任一字段,作用域关键字不起作用,这可能会暴露安全问题。)

            DataContract public struct Number 
    {
    DataMember public double Num1;
    DataMember public double Num2;
    public Number(double num1, double num2)
    {
    this.Num1 = num1;
    this.Num2 = num2;
    }
    }

    DataContract 的属性
    Name / Namespace:自定义名称和命名空间。


    DataMember 的属性
    Name:自定义名称。
    IsRequired:指示该成员序列化前必须被赋值。

    DataContractSerializer 实际上序列化是一个过程,不过这个过程大多徐情况下被系统自动实现了。默认情况下,WCF 使用 DataContractSerializer 引擎对相关参数进行序列化,这也是 WCF 推荐的方式。另外一个选择是 XmlSerializer,也就是 ASP.NET Web Service 所使用的序列化引擎。XmlSerializer 仅支持 DataContractSerializer 所支持的部分类型,但它允许你使用 XmlAttributeAttribute 等特性对序列化生成的 XML 进行更多的控制。

    DataContractSerializer 支持的类型:
    支持所有的基本类型,还包括 XmlElement 和 DateTime 这样的常用类型。
    支持使用 DataContractAttribute 标记的类型。
    支持使用 SerializableAttribute 标记或者实现 ISerializable 接口的类型。
    实现 IXmlSerializable 接口的类型。
    大多数集合(含泛型)类型,包括常用的 Array、List、IList 等。

    KnownTypes
    在OO中,对象继承是很常见的,但如果在WCF直接使用继承后,实际上被分成了2个独立的类。这时就需要使用KnownType来标识,这样在客户端生成代理后就变成继承的了。
    还可以通过配置文件指定

    4. 消息契约(Message Contract)
    消息契约可以算是数据契约的一个分类,专为SOAP而生的。可以控制消息的格式。数据是放在Header 还是Body中。

    非类型化(Untyped)
    可以通过System.ServiceModel.Channels.Message类来直接构造消息,不过这个必须指定动作的地址,用来确定是那个操作被执行。 这样变可以不用构建类型了,不过会很累。。

    非包装(Unwrapped)
    WCF对消息序列化的时候,可以决定是否对消息进行包装。 如果,和其他系统整合的话,可能需要去掉包装,手动控制。

    样式
    可以通过设置XmlSerializerFormat的Style和Use可以使用样式

    使用XMLReader
    可以通过Message的GetReaderAtBodyContents 可以获取消息的XML部分

    5. 错误契约(Fault Contract)
    错误契约Fault Contract主要是来告诉一个服务或操作产生错误后,这个消息是什么样子的。 在SOA中,并没有限制客户端是什么平台,事实上,连服务端也是。只有契约没有变。

    ======================================华丽的分割线=================================================

    在WCF中,契约分为四种,它们分别为:

    1. 用于定义服务操作的服务契约:Service Contract

    这种级别的契约又包括两种:ServiceContract和OperationContract

    ServiceContract用于类或者结构上,用于指示WCF此类或者结构能够被远程调用,而OperationContract用于类中的方法(Method)上,用于指示WCF该方法可被远程调用。

      [ServiceContract]

    public interface ICalculate

    {

    [OperationContract]

    double Add(double a, double b);

    }
    1. 用于自定义数据结构的数据契约:Data Contract

    数据契约也分为两种:DataContract和DataMember.DataContract用于类或者结构上,指示 WCF此类或者结构能够被序列化并传输,而DataMember只能用在类或者结构的属性(Property)或者字段(Field)上,指示WCF该属性或者字段能够被序列化传输。
    我们还可以使用 DataContractAttribute、DataMemberAttribute 来标注自定义数据类型,这样我们就可以在服务方法中传递复杂的数据体了。使用之前,我们需要添加 System.Runtime.Serialization.dll 引用。由此我们可以看出其基本的开发模式,那就是使用 ServiceContract、OperationContract 执行运算,而使用 DataContract、DataMember 作为可序列化的数据载体。当然,我们也可以使用 "[Serializable]" 代替 "[DataContract]"。

     [DataContract]

    public class User

    {

    int _age = 27;

    [DataMember]

    public int Age

    {

        get { return _age; }

        set { _age = value; }

      }

      string _userName = "wang.yq";

      [DataMember]

      public string UserName

      {

        get { return _userName; }

        set { _userName = value; }

       }

    }


    用于自定错误异常的异常契约:Fault Contract

    FaultContract用于自定义错误异常的处理方式,默认情况下,当服务端抛出异常的时候,客户端能接收到异常信息的描述,但这些描述往往格式统一,有时比较难以从中获取有用的信息,此时,我们可以自定义异常消息的格式,将我们关心的消息放到错误消息中传递给客户端,此时需要在方法上添加自定义一个错误消息的类,然后在要处理异常的函数上加上FaultContract,并将异常信息指示返回为自定义格式。

    1. 用于控制消息格式的消息契约:Message Contract

    简单的说,它能自定义消息格式,包括消息头,消息体,还能指示是否对消息内容进行加密和签名。

    ServiceContract

    • ConfigurationName: 其设置信息在配置文件中的名称。
    • Name / Namespace:自定义该服务契约的名称和命名空间。建议设置服务契约的 Name 和 Namespace,这样生成的客户端的代理文件会使用自定义名称来命名相关代理类型,即便我们日后对服务器端的契约名称进行重构也不会影响到客户端。
    • SessionMode:设置服务契约的 Session 方式,包括 Allowe、NotAllowed、Required。SessionMode 需要相应的 Binding 支持,默认情况下会自动启用,另外我们还会和 ServiceBehaviorAttribute.InstanceContextMode 配合使用来管理服务对象的生命周期。
    • CallbackContract:设置 duplex (双向通信)模式时的回调类型。
    • ProtectionLevel:指定消息保护方式,可以对消息进行加密和签名处理。

    OperationContract

    • AsyncPattern:用于定义异步服务方法。
    • IsInitiating:指示服务方法能否启动一个 Session。
    • IsTerminating:指示服务方法调用完成是否结束 Session。

    DataContract

    • Name / Namespace:自定义名称和命名空间。

    DataMember

    • Name:自定义名称。
    • IsRequired:指示该成员序列化前必须被赋值。

    契约是独立于平台的么?

        WCF作为一种能够跨平台的体系框架,其应用肯定会有异构,异网的情况发生,那么作为通讯依据的契约能否自动适用于上述情况呢?答案是肯定的,契约是独立于平台之外的,它只约束通讯的双方应该遵守什么样的规则,而丝毫不管双方各自采用的是什么样的技术和什么样的操作系统,也只有这样,WCF才能有真正的生命力。

    契约和以往哪种技术比较相像,又有什么不同?

        如果非要拿契约和以往的技术相比较的话,契约和asp.net xml web service的声明性编程模型甚是相似,比如在web service中在类上标记WebServiceAttribute便可以将此类用于远程调用,而将方法添加WebMethondAttribute也可以将其暴露给远程客户端,这和WCF中的ServiceContract和OperationContract简直如出一辙,但不同的是,WCF中的契约要比Xml Web Service中的要详尽的多,比如ServiceContract和OperationContract可以直接使用在接口上面,而实现该接口的类就继承了这种契约声明,自动拥有契约所规范的动作和行为,这就使得程序员更方便的使用面向接口的编程方式,可以使同一服务拥有不同的实现,在新旧版本升级的同时,能够使新老版本共同运行。

  • 相关阅读:
    响应式设计的 5 个 CSS 实用技巧
    iframe的高度自适应的方法
    HDOJ1285 比赛排名(拓扑排序)
    GENIA项目GENIA语料库
    HDOJ1102 修路问题(最小生成树Prim)
    二叉树的一些操作
    GENIA项目综述论文(E99)
    GENIA项目主页
    读《统计自然语言处理》有笔记——语料库与知识词汇库
    HDOJ2535 ( Vote ) 【水题】
  • 原文地址:https://www.cnblogs.com/scy251147/p/2261592.html
Copyright © 2020-2023  润新知