`
varsoft
  • 浏览: 2546758 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

[原创] WCF技术剖析之十八:消息契约(Message Contract)和基于消息契约的序列化

阅读更多

[爱心链接:拯救一个25岁身患急性白血病的女孩[内有苏州电视台经济频道《天天山海经》为此录制的节目视频(苏州话)]]在本篇文章中,我们将讨论WCF四大契约(服务契约、数据契约、消息契约和错误契约)之一的消息契约(Message Contract)。服务契约关注于对服务操作的描述,数据契约关注于对于数据结构和格式的描述,而消息契约关注的是类型成员与消息元素的匹配关系。

我们知道只有可序列化的对象才能通过服务调用在客户端和服务端之间进行传递。到目前为止,我们知道的可序列化类型有两种:一种是应用了System.SerializableAttribute特性或者实现了System.Runtime.Serialization.ISerializable接口的类型;另一种是数据契约对象。对于基于这两种类型的服务操作,客户端通过System.ServiceModel.Dispatcher.IClientMessageFormatter将输入参数格式化成请求消息,输入参数全部内容作为有效负载置于消息的主体中;同样地,服务操作的执行结果被System.ServiceModel.Dispatcher.IDispatchMessageFormatter序列化后作为回复消息的主体。

在一些情况下,具有这样的要求:当序列化一个对象并生成消息的时候,希望将部分数据成员作为SOAP的报头,部分作为消息的主体。比如说,我们有一个服务操作采用流的方式进行文件的上载,除了以流的方式传输以二进制表示的文件内容外,还需要传输一个额外的基于文件属性的信息,比如文件格式、文件大小等。一般的做法是将传输文件内容的流作为SOAP的主体,将其属性内容作为SOAP的报头进行传递。这样的功能,可以通过定义消息契约来实现。

一、 消息契约的定义

消息契约和数据契约一样,都是定义在数据(而不是功能)类型上。不过数据契约旨在定义数据的结构(将数据类型与XSD进行匹配),而消息契约则更多地关注于数据的成员具体在SOAP消息中的表示。消息契约通过以下3个特性进行定义:System.ServiceModel.MessageContractAttributeSystem.ServiceModel.MessageHeaderAttributeSystem.ServiceModel.MessageBodyMemberAttribute。MessageContractAttribute应用于类型上,MessageHeaderAttribute和MessageBodyMemberAttribute则应用于属性或者字段成员上,表明相应的数据成员是一个基于SOAP报头的成员还是SOAP主体的成员。先来简单介绍一下这3个特性:

1、MessageContractAttribute

通过在一个类或者结构(Struct)上应用MessageContractAttribute使之成为一个消息契约。从MessageContractAttribute的定义来看,MessageContractAttribute大体上具有以下两种类型的属性成员:

  • ProtectionLevel和HasProtectionLevel:表示保护级别,在服务契约中已经对保护级别作了简单的介绍,WCF中通过System.Net.Security.ProtectionLevel枚举定义消息的保护级别。一般有3种可选的保护级别:None、Sign和EncryptAndSign
  • IsWrapped、WrapperName、WrapperNamespace:IsWrapped表述的含义是是否为定义的主体成员(一个或者多个)添加一个额外的根节点。WrapperName和WrapperNamespace则表述该根节点的名称和命名空间。IsWrapped、WrapperName、WrapperNamespace的默认是分别为true、类型名称和http://tempuri.org/
   1: [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = false)]
<!--CRLF-->
   2: public sealed class MessageContractAttribute : Attribute
<!--CRLF-->
   3: {  
<!--CRLF-->
   4:     //其他成员
<!--CRLF-->
   5:     public bool         HasProtectionLevel { get; }
<!--CRLF-->
   6:     public ProtectionLevel    ProtectionLevel { get; set; }
<!--CRLF-->
   7: 
<!--CRLF-->
   8:     public bool     IsWrapped { get; set; }
<!--CRLF-->
   9:     public string     WrapperName { get; set; }
<!--CRLF-->
  10:     public string     WrapperNamespace { get; set; }
<!--CRLF-->
  11: }
<!--CRLF-->

下面的代码中将Customer类型通过应用MessageContractAttribute使之成为一个消息契约。ID和Name属性通过应用MessageHeaderAttribute定义成消息报头(Header)成员,而Address属性则通过MessageBodyMemberAttribute定义成消息主体(Body)成员。后面的XML体现的是Customer对象在SOAP消息中的表现形式。

   1: [MessageContract]
<!--CRLF-->
   2: public class Customer
<!--CRLF-->
   3: {
<!--CRLF-->
   4:     [MessageHeader(Name = "CustomerNo", Namespace = "http://www.artech.com/")]
<!--CRLF-->
   5:     public Guid ID
<!--CRLF-->
   6:     { get; set; }
<!--CRLF-->
   7: 
<!--CRLF-->
   8:     [MessageHeader(Name = "CustomerName", Namespace = "http://www.artech.com/")]
<!--CRLF-->
   9:     public string Name
<!--CRLF-->
  10:     { get; set; }
<!--CRLF-->
  11: 
<!--CRLF-->
  12:     [MessageBodyMember(Namespace = "http://www.artech.com/")]
<!--CRLF-->
  13:     public string Address
<!--CRLF-->
  14:     { get; set; }
<!--CRLF-->
  15: }
<!--CRLF-->
   1: <s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<!--CRLF-->
   2:     <s:Header>
<!--CRLF-->
   3:         <a:Action s:mustUnderstand="1">http://tempuri.org/IOrderManager/ProcessOrder</a:Action>
<!--CRLF-->
   4:         <h:CustomerName xmlns:h="http://www.artech.com/">Foo</h:CustomerName>
<!--CRLF-->
   5:         <h:CustomerNo xmlns:h="http://www.artech.com/">2f62405b-a472-4d1c-8c03-b888f9bd0df9</h:CustomerNo>
<!--CRLF-->
   6:     </s:Header>
<!--CRLF-->
   7:     <s:Body>
<!--CRLF-->
   8:         <Customer xmlns="http://tempuri.org/">
<!--CRLF-->
   9:             <Address xmlns="http://www.artech.com/">#328, Airport Rd, Industrial Park, Suzhou Jiangsu Province</Address>
<!--CRLF-->
  10:         </Customer>
<!--CRLF-->
  11:     </s:Body>
<!--CRLF-->
  12: </s:Envelope> 
<!--CRLF-->

如果我们将IsWrapped的属性设为false,那么套在Address节点外的Customer节点将会从SOAP消息中去除。

   1: [MessageContract(IsWrapped = false)]
<!--CRLF-->
   2: public class Customer
<!--CRLF-->
   3: {
<!--CRLF-->
   4:       //省略成员
<!--CRLF-->
   5: }
<!--CRLF-->
   1: <s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<!--CRLF-->
   2:     ......
<!--CRLF-->
   3:     <s:Body>
<!--CRLF-->
   4:         <Address xmlns="http://www.artech.com/">#328, Airport Rd, Industrial Park, Suzhou Jiangsu Province</Address>
<!--CRLF-->
   5:     </s:Body>
<!--CRLF-->
   6: </s:Envelope>
<!--CRLF-->

我们同样可以自定义这个主体封套(Wrapper)的命名和命名空间。下面我们就通过将MessageContractAttribute的WrapperName和WrapperNamespace属性设为Cust和http://www.artech.com/。

   1: [MessageContract(IsWrapped = true, WrapperName = "Cust", WrapperNamespace = "http://www.artech.com/")]
<!--CRLF-->
   2: public class Customer
<!--CRLF-->
   3: {
<!--CRLF-->
   4:     //省略成员
<!--CRLF-->
   5: }
<!--CRLF-->
   1: <s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<!--CRLF-->
   2:     ......
<!--CRLF-->
   3:     <s:Body>
<!--CRLF-->
   4:         <Cust xmlns="http://www.artech.com/">
<!--CRLF-->
   5:             <Address>#328, Airport Rd, Industrial Park, Suzhou Jiangsu Province</Address>
<!--CRLF-->
   6:         </Cust>
<!--CRLF-->
   7:     </s:Body>
<!--CRLF-->
   8: </s:Envelope>
<!--CRLF-->

2、MessageHeaderAttribute

MessageHeaderAttribute和MessageBodyMemberAttribute分别用于定义消息报头成员和消息主体成员,它们都有一个共同的基类:System.ServiceModel.MessageContractMemberAttribute。MessageContractMemberAttribute定义了以下属性成员:HasProtectionLevel、ProtectionLevel、Name和Namespace。

   1: public abstract class MessageContractMemberAttribute : Attribute
<!--CRLF-->
   2: {   
<!--CRLF-->
   3:     public bool             HasProtectionLevel { get; }
<!--CRLF-->
   4:     public ProtectionLevel     ProtectionLevel { get; set; }
<!--CRLF-->
   5: 
<!--CRLF-->
   6:     public string             Name { get; set; }
<!--CRLF-->
   7:     public string             Namespace { get; set; }
<!--CRLF-->
   8: }
<!--CRLF-->

通过在属性或者字段成员上应用MessageHeaderAttribute使之成为一个消息报头成员。MessageHeaderAttribute定义了以下3个属性,如果读者对SOAP规范有一定了解的读者,相信对它们不会陌生。

注:在《WCF技术剖析(卷1)》中的第六章有对SOAP 1.2的基本规范有一个大致的介绍,读者也可以直接访问W3C网站下载官方文档。

  • Actor:表示处理该报头的目标节点(SOAP Node),SOAP1.1中对应的属性(Attribute)为actor,SOAP 1.2中就是我们介绍的role属性
  • MustUnderstand:表述Actor(SOAP 1.1)或者Role(SOAP 1.2)定义的SOAP节点是否必须理解并处理该节点。对应的SOAP报头属性为mustUnderstand
  • Relay:对应的SOAP报头属性为relay,表明该报头是否需要传递到下一个SOAP节点
   1: [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
<!--CRLF-->
   2: public class MessageHeaderAttribute : MessageContractMemberAttribute
<!--CRLF-->
   3: {
<!--CRLF-->
   4:     public string     Actor { get; set; }
<!--CRLF-->
   5:     public bool     MustUnderstand { get; set; }
<!--CRLF-->
   6:     public bool     Relay { get; set; }
<!--CRLF-->
   7: }
<!--CRLF-->

同样使用上面定义的Customer消息契约,现在我们相应地修改了ID属性上的MessageHeaderAtribute设置:MustUnderstand = true, Relay=true, Actor=http://www.w3.org/ 2003/05/soap-envelope/role/ultimateReceiver。实际上将相应的SOAP报头的目标SOAP节点定义成最终的消息接收者。由于http://www.w3.org/2003/05/soap-envelope/role/ultimateReceiver是SOAP 1.2的预定义属性,所以这个消息契约之后在基于SOAP 1.2的消息版本中有效。后面给出的为对应的SOAP消息。

   1: [MessageContract(IsWrapped =true, WrapperNamespace="http://www.artech.com/")]public class Customer
<!--CRLF-->
   2: {
<!--CRLF-->
   3:     //其他成员
<!--CRLF-->
   4:     [MessageHeader(Name="CustomerNo", Namespace = "http://www.artech.com/" ,MustUnderstand = true, Relay=true, Actor="http://www.w3.org/2003/05/soap-envelope/role/ultimateReceiver" )]
<!--CRLF-->
   5:     public Guid ID
<!--CRLF-->
   6:     { get; set; }
<!--CRLF-->
   7

  


  
分享到:
评论

相关推荐

    WCF序列化案例

    综上所述,WCF序列化是实现服务间数据交换的核心技术,理解并掌握其原理和配置,对于有效利用WCF构建高效、可靠的分布式系统至关重要。在实际项目中,开发者应根据需求选择合适的序列化策略,以优化性能和提高代码的...

    数据契约之WCF与序列化

    在WCF(Windows Communication Foundation)中,数据契约(DataContract)是一种用于定义可序列化的自定义数据类型的方式,使得这些数据可以在服务端和客户端之间安全、高效地传输。数据契约是WCF服务的核心组成部分...

    WCF技术剖析(卷1)

    本书《WCF技术剖析(卷1)》深入探讨了WCF的各个方面,为读者提供了一个全面的理解和实践WCF的平台。以下是基于该书和WCF技术的一些关键知识点: 1. **服务导向架构(SOA)基础**:WCF设计的核心理念是基于服务导向...

    构建WCF面向服务的应用程序系列课程(2):WCF契约设计

    - **消息契约(Message Contract)**:精细控制消息的结构,包括消息头和消息体。 **2. 数据契约设计** 数据契约是WCF中的基础组件,用于定义可序列化的数据类型。通过使用`[DataContract]`和`[DataMember]`特性,...

    WCF技术剖析pdf

    WCF整合了.NET Framework中的Web服务、Remoting、Message Queuing(MSMQ)和Enterprise Services等多个通信技术,旨在简化企业级应用的构建和维护。 **一、WCF的核心概念** 1. **服务**: WCF中的核心元素是服务,...

    WCF系列学习源码

    `WCF_序列化`与`WCF_序列化下`这两个文件着重展示了如何使用.NET内置的XML序列化器和数据契约序列化器进行数据转换。同时,它们也演示了如何自定义数据契约以满足特定需求,以及如何处理序列化时的异常。 3. **WCF...

    构建WCF面向服务的应用程序系列课程:WCF契约设计

    通过使用`DataContract`和`DataMember`特性,我们可以指定哪些类或字段将被序列化和反序列化。例如: ```csharp [DataContract] public class CalculatorRequest { [DataMember] public double Num1 { get; set; ...

    WCF分布式开发技术讲座

    WCF整合了.NET Framework中的多种通信技术,如ASMX、Remoting、Message Queuing (MSMQ) 和Web Services,提供了一种统一的编程模型。 在“WCF分布式开发技术讲座”中,我们将会深入探讨以下关键知识点: 1. **WCF...

    WCF服务契约与复杂类型序列化DEMO

    在WCF中,复杂类型通常作为数据契约(Data Contract)的一部分进行序列化和反序列化。数据契约使用`[DataContract]`特性标记类,并使用`[DataMember]`特性标记类的成员。例如: ```csharp [DataContract] public ...

    WCF技术专题:WCF入门与进阶

    7. **数据转移优化**: 数据契约支持序列化和反序列化,可以有效减少数据传输量。 8. **错误处理与诊断**: 提供详细的跟踪、日志记录和故障恢复机制,便于调试和问题定位。 **四、WCF的挑战与替代技术** 虽然WCF...

    (3):契约版本处理-WCF课件

    通过本课件的学习,我们可以了解到在WCF中处理契约版本的方法和技术。正确的版本控制策略不仅能提高系统的灵活性,还能降低因服务升级而带来的风险。开发者应根据实际情况选择合适的版本控制方式,确保服务的稳定性...

    WCF基础入门学习资料

    对于初学者 会有帮助 契约  WCF所有的服务都是公开为契约,当你使用这个服务是就比约遵循一定的契约。契约的表示就想webservice里的表示,也是通过属性...消息契约(Message Contract):定义直接与服务交互的消息。

    WCF 技术剖析 +源码

    **WCF技术剖析** Windows Communication Foundation(WCF)是微软.NET框架中的一种全面的服务托管和通信框架,旨在为开发人员提供构建分布式应用程序的强大工具。它整合了.NET框架中原本分散的若干通信技术,如ASP...

    wcf数据契约

    在WCF中,数据契约(Data Contract)扮演着至关重要的角色,它是服务和客户端之间交换数据的标准格式。数据契约定义了数据的结构和类型,确保不同系统之间的互操作性。 ### 1. 数据契约的概念 数据契约是一种接口...

    构建WCF面向服务的应用程序系列课程(2):WCF契约设计 (Level 200)

    当开发者需要更加细致地控制 服务契约设计,消息序列化以及协议的选择时,也可以通过WCF来帮助我们完成。在本次的课程中,我们将向大家介绍设计服务契约,数据契约和消息契约的实用 指导,向大家展示什么时候,以及...

    构建WCF面向服务的应用程序系列课程(2):WCF契约设计.zip

    理解并熟练掌握数据契约、操作契约和服务配置契约的创建和管理,有助于构建健壮、可扩展和安全的WCF服务。同时,考虑到版本控制、异常处理、安全性和互操作性,将使你的WCF应用更具灵活性和可靠性。

    WCF技术剖析.pdf

    《WCF技术剖析》从WCF的终结点谈起,对终结点的三要素进行了全面而深入的介绍,帮助读者了解地址、绑定和契约的本质。 通过本书对序列化的深入讲解,读者可了解WCF进行操作方法调用与消息之间转化的本质;深入剖析...

    WCF序列化小实例

    5. **客户端消费服务**:创建一个WCF客户端,调用服务的方法,此时就会涉及数据的序列化和反序列化。 ```csharp var client = new MyServiceClient(); Person person = new Person() { Name = "John", Age = 30 }; ...

Global site tag (gtag.js) - Google Analytics