《WCF技术内幕》翻译28:第2部分_第5章_消息:使用消息头(中)

《WCF技术内幕》翻译28:第2部分_第5章_消息:使用消息头(中)

大家好,又见面了,我是全栈君。

MessageHeaders类型

因为SOAP消息可能包含很多消息头块,所以在一个Message类型里,我们需要一种表示一组消息头块对象的方法。MessageHeaders就是这个作用,并且它定义了一个 MessageHeaders类型的只读属性Headers。Headers属性是我们在Message里增加、修改、查询和移除MessageHeader的主要方式。在某种意义上,本节主要是讲解MessageHeaders类型,以及可以应用到Message类型的Headers属性上的所有信息。与Message相反,在实例化一个Message之后,我们可以随便修改Headers属性的内容。MessageHeaders是一个
具体类,而不是抽象类,它不包含工厂方法。这一点值得注意,因为本章讨论过的类型都是抽象的并且定义了工厂方法。
像前面提到的一样, 
MessageHeaders,在一定层次上,是一组 MessageHeader对象。MessageHeader类型的对象模型,奇怪的是少了一个可以返回MessageHeader对象集合的成员。作为替代,MessageHeaders实现了IEnumerable<MessageHeaderInfo> and  IEnumerable接口。这意味着我们可以简单地迭代 MessageHeaders类型来查看所有的消息头块(在MessageHeaders对象赋值以后)。
 
注意 
为了完整,我必须提下MessageHeaderInfo类型,它是 MessageHeader的基类。MessageHeaderInfo定义了几个表示SOAP消息头块的属性,比如:Actor、MustUnderstand等等。太白地说,我们看不出这个类型存在的理由,因为 MessageHeader是抽象的。

创建一个MessageHeaders对象

MessageHeaders类型定义了三个公开的构造函数。这里要着重指出的是绝大多数开发人员都不会直接使用这些构造函数,因为 Message类型(子类型)底层机制会为你调用其中的一个构造函数。如果你要选择继承Message类型的话,或许需要调用其中一个构造函数去设置Message的消息头部分。
其中一个构造函数接受MessageHeaders类型的参数。构造函数会对 MessageHeaders执行深拷贝,并把它存储在MessageHeaders实例里。
另外一个构造函数接受一个MessageVersion类型的参数,如你所料,这是设置 MessageHeaders 实例的SOAP version和WS-Addressing version。最后一个构造函数接受一个MessageVersion类型和一个 Int32类型的参数。这个构造函数设置SOAP和WS-Addressing的版本,同样包括内部消息头块list里元素的个数。记住实际元素的个数可以超过Int32设置的个数。如果我们知道将要增加到 MessageHeaders对象里的消息头的个数,使用这个重载方法,它会提升性能,因为在对象的整个生命周期里早期的时候,已经设置好了合适的存储空间。

添加一个MessageHeader

一旦MessageHeaders对象实例化完毕,我们需要给它增加一个或者多个 MessageHeader对象。MessageHeaders类型定义了接受一个MessageHeader 对象作为参数的Add方法。然后把插入 MessageHeader 对象插入到消息头块列表的最末端。
如果我们需要把MessageHeader对象插入到特定的位置,我们可以使用 Insert方法。它接受一个Int32 和MessageHeader类型的参数。 Int32类型的参数表示要插入的位置,MessageHeader参数是要插入的对象。非常有意思的是MessageHeaders把MessageHeader对象存放在一个数组结构中。如果我们传递的索引大于数组的大小,方法会抛出一个ArgumentOutOfRangeException。

获取MessageHeader的值

当一个程序接收、解码和反序列化一个stream到Message对象的时候,我们经常需要获取一个或者多个消息头块的值。因为 MessageHeader类型提供了多种方式,我们必须求助于MessageHeaders类型。
一种方式,我们在MessageHeaders对象里获取特定的MessageHeader,就是使用索引。为了找到特定消息头块的索引,我们可以调用两个 FindHeader方法。它们都接受表示nam和namespace的String参数。其中一个方法接受一个表示能够与消息头块交互的actor的String参数。它们的返回值都是 Int32。如果没有匹配的消息头块,FindHeader回返回-1。如果找到多个消息头块,会返回第一个匹配的消息头块的索引。
备注 
我的观点,这不是一个良好的设计, 它违反了Microsoft文档里已经规定的最佳实践和关于framework设计的内部标准。它应该命名为为TryFindHeader或者如果没有找到匹配的消息头就应该抛出一个异常。抛开我的看法,当调用 FindHeader方法的时候,我们必须检查返回的值是否为-1。
在找到消息头块的索引以后(只要不是-1),我们随后就可以检查消息头块的值。为此,我们调用其中一个 GetHeader<T> 方法。重载的方法接受各种参数,包括一个消息头块的索引和一个自定义的序列化器。其中三个重载方法接受的String参数可以映射到 FindHeader方法接受的参数上。内部来看,这些重载方法调用适当的FindHeader方法,并且检查返回的值是否是-1.与FindHeader相反,如果没有找到匹配的消息头块,GetHeader<T>方法会抛出个异常。

复制一个MessageHeaders对象

MessageHeaders类型提供了几种机制从 MessageHeaders对象去复制一个或者所有的消息头块。为了看看这个功能有何用处,思考一下,当需要根据一个接受到的Message来创建一个新的Message的时候,需要什么数据。如果接受的Message包含一个PurchaseOrderInfo消息头块,我们或许需要包含一个复制的消息头块在回复的Message里。虽然可以使用相同的值重新创建一个新的消息头块,但是复制一个存在的消息头块到一个新的Message里会简单很多。
这两个CopyHeaderFrom方法提供了复制一个消息头块的值到 MessageHeaders实例里的能力。它们都接受Int32参数作为消息头块的索引。并且会把消息头块也放到内部数组的末端,没有提供指定位置的是方法。其中一个CopyHeaderFrom方法接受一个Message对象作为参数,而另外一个接受一个MessageHeaders对象作为参数。内部来看,前者通过Message类型里的Headers属性调用后者。
两个CopyHeadersFrom方法提供了复制整个 MessageHeaders对象内容的能力、同样有一个方法接受一个Message作为参数,另外一个方法接受一个MessageHeaders参数。源数据消息头块被追加到目的消息头块的尾部。换句话说,这个操作不是一个替换,而是对现有消息头块的串联。这可能有一些意外的结果,如下所示:

// create a Message创建一个消息

Message message = Message.CreateMessage(

        MessageVersion.Soap12WSAddressing10,

        “urn:SomeAction”,

        “Hello WCF”);

// add two new headers to the Message

message.Headers.To = new Uri(“http://wintellect.com/Original”);

message.Headers.Add(MessageHeader.CreateHeader(“test”, “test”, “test”));

    

// create a new Message创建一个新的消息

Message message2 = Message.CreateMessage(

        MessageVersion.Soap12WSAddressing10,

        “urn:SomeAction2”,

        “Hello WCF2”);

// add two new headers to the Message

message2.Headers.To = new Uri(“http://wintellect.com/Test”);

message2.Headers.Add(MessageHeader.CreateHeader(“test”, “test”, “test”));

    

// copy the headers from the first Message into the second one复制消息头块

message2.Headers.CopyHeadersFrom(message);

    

// show the contents

Console.WriteLine(message2.ToString());

When this code executes, the following output is generated:
执行代码,产生如下结果:

<s:Envelope xmlns:a=”http://www.w3.org/2005/08/addressing”

xmlns:s=”http://www.w3.org/2003/05/soap-envelope”>

<s:Header>

        <a:Action s:mustUnderstand=”1″>urn:SomeAction2</a:Action>

        <a:To s:mustUnderstand=”1″>http://wintellect.com/Test</a:To>

        <test xmlns=”test”>test</test>

        <a:Action s:mustUnderstand=”1″>urn:SomeAction</a:Action>

        <a:To s:mustUnderstand=”1″>http://wintellect.com/Original</a:To>

        <test xmlns=”test”>test</test>

</s:Header>

<s:Body>

        <string xmlns=”http://schemas.microsoft.com/2003/10/Serialization/”>

            Hello WCF2

        </string>

</s:Body>

</s:Envelope>

哎呦!这个Message显然不对。事实上, CopyHeaderFrom方法遇到相同的问题(重复的消息头块)。换句话说,复制消息头是件头疼的事情,开发人员需要检查目标Message里是否有重复的消息头块、

序列化一个MessageHeaders对象

MessageHeaders类型定义了几个序列化 MessageHeaders对象部分或者整体的方法。与Message和MessageHeader类型一样,MessageHeaders 类型上的序列化方法也是以单词Write开头。最简单的方法是 WriteHeader方法。如其名字暗示的一样,这个方法就是序列化一个消息头块。它接受一个Int32 和一个XmlDictionaryWriter作为参数。 Int32表示消息头块的索引,XmlDictionaryWriter,正如你猜测的一样,执行实际的序列化和编码工作。WriteHeader方法调用其它的MessageHeaders的序列化方法:WriteStartHeader和WriteHeaderContents。 WriteStartHeader方法,也和其名字暗示的一样,序列化开发的消息头块,而WriteHeaderContents方法序列化消息头块的内容。
没有一步序列化全部MessageHeaders内容的机制。唯一的方法就是迭代所有的消息头块,并序列化每一个消息头块。实际上,我们很少会有这样的需求,就是在序列化一个 Message的上下文环境外,去序列化消息头块。因此,Message类型定义了序列化真个内容的WriteMessage方法。此方法在Message类型上的实现,会迭代并序列化每一个消息头块。



 本文转自 frankxulei 51CTO博客,原文链接:
http://blog.51cto.com/frankxulei/318581
,如需转载请自行联系原作者

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/107968.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 小米手机计算机无法归零,小米体脂秤不归零怎么调

    1、放平体重秤秤角。电子体重秤是比较敏感的,所以先确认四个秤脚是否摆放平稳、否有悬空、否有杂物,另外选择坚实的地面;2、移动后数据稳定再称重。第一次称完下来等数据稳定归零后再进行第二次测量;3、关闭忽略30秒之内的称重数据功能。小米体重秤有个选项,会自动忽略30秒之内的称重数据,也就是说前一个人刚称重完,30秒内另一个人站上去,得不到准确的数据。可以选择关闭该功能或者等30秒后再称重;4、重新绑定…

    2022年4月9日
  • ajax处理跨域_django跨域解决方案

    ajax处理跨域_django跨域解决方案原文:Javascript跨域和Ajax跨域解决方案 摘要:跨域请求,顾名思义,就是一个站点中的资源去访问另外一个不同域名站点上的资源。这种情况很常见,比如说通过style标签加载外部样式表文件、通过img标签加载外部图片、通过script标签加载外部脚本文件、通过Webfont加载字体文件等等。默认情况下,脚本访问文档属性等数据采用的是同源策略(Sameorigi…

    2022年8月24日
  • java中notify作用_notify的过去式

    java中notify作用_notify的过去式用Java通知vsnotifyAllnotify和notifyAll方法之间有什么区别是棘手的Java问题之一,这很容易回答但是一旦访问者提出后续问题,你要么感到困惑,要么无法提供明确的答案?notify和notifyAll之间的主要区别在于notify方法只通知一个Thread,notifyAll方法将通知在该监视器上等待的所有线程或锁定。顺便说一句,这是你在各地阅读的内容,坦率地说,这句话…

    2022年9月8日
  • 使用Protostuff实现序列化与反序列化

    使用Protostuff实现序列化与反序列化使用Protostuff实现序列化与反序列化(1)Protobuf介绍GoogleProtocolBuffer(简称Protobuf)是Google公司内部的混合语言数据标准,目前已经正在使用的有超过48,162种报文格式定义和超过12,183个.proto文件。他们用于RPC系统和持续数据存储系统。ProtocolBuffers是一种轻便高效的结构化数…

    2022年5月4日
  • matlab中wavedec2,wavedec2函数详解[通俗易懂]

    matlab中wavedec2,wavedec2函数详解[通俗易懂]很多人对小波多级分解的wavedec2总是迷惑,今天就详释她!wavedec2函数:1.功能:实现图像(即二维信号)的多层分解,多层,即多尺度.2.格式:[c,s]=wavedec2(X,N,’wname’)[c,s]=wavedec2(X,N,Lo_D,Hi_D)(我不讨论它)3.参数说明:对图像X用wname小波基函数实现N层分解,这里的小波基函数应该根据实际情况选择,具体选择办法可以搜之或者…

    2022年7月24日
  • SAP 常用的BAPI

    SAP 常用的BAPIBAPI_ALE_MODEL_GETBAPI_BARCODE_SENDLISTBAPI_ANSWER_READMULTIPLEBAPI_APPCOMP_READMULTIPLEBAPI_PROCDIA_READMULTIPLEBAPI_PROCDIA_WRITEMULTIPLEBAPI_DIAVAR_READMULTIPLEBAPI_DIAVAR_WRITEMULTIPLEBAPI_PROCE

    2022年7月24日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号