《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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 倒计时应用countdown_countdown timer

    倒计时应用countdown_countdown timerCountDownTimerCountDownTimer是android自带的一个倒计时类,使用这个类可以很简单的实现倒计时功能CountDownTimer的实现方式newCountDownTimer(6000,1000){//第一个参数表示的是倒计时的总时间,第二参数表示的是倒计时的间隔时间。@OverridepublicvoidonTick(longmillisUntilFi…

    2022年9月18日
    3
  • javah -jni_java this用法

    javah -jni_java this用法目录一、native关键字二、javah命令一、native关键字native即JNI,JavaNativeInterface凡是一种语言,都希望是纯。比如解决某一个方案都喜欢就单单这个语言来写即可。Java平台有个用户和本地C代码进行互操作的API,称为JavaNativeInterface(Java本地接口)。二、javah命令1首先找到java文件目…

    2022年9月24日
    2
  • 使用API Monitor监测到目标程序对系统API函数的调用(常用分析工具)

    使用API Monitor监测到目标程序对系统API函数的调用(常用分析工具)本文通过一个具体的问题实例讲述如何使用 APIMonitor 工具

    2025年12月4日
    3
  • springboot的启动流程及原理_精馏的原理及流程

    springboot的启动流程及原理_精馏的原理及流程1.springboot的启动类入口@SpringBootApplication@ComponentScan(basePackages={“cn”})publicclassSpringBootDemo{publicstaticvoidmain(String[]args){SpringApplication.run(SpringBootDemo.class);}}可以看出,Annotation定义(@SpringBootApplicati

    2022年8月21日
    6
  • JAVA环境变量配置步骤详细教程

    JAVA环境变量配置步骤详细教程概述Java的环境配置并不是特别难,但是对刚上手的新手来说确实是一个大问题首先下载jdk安装包网址进去选择自己需要的版本下载就行了,这里演示的是jdk-8u131-windows-x64_8.0.1310.11,版本稍老,道理一样安装下载后直接双击运行,这时会让你选择安装路径默认是C盘,这里改成自己想要存放的地方,小编放在了D盘的ROUTE文件夹下的java目录下的jdk1.8.0_131然后点击确定,下一步,开始跑进度条,但是不一会就会弹窗出来jre的安装路径我们点击更改,然后选择一个别的文

    2022年7月8日
    22
  • idea设置默认maven路径_idea查看maven路径

    idea设置默认maven路径_idea查看maven路径在idea中每次创建maven都要调整位置是不是很烦~可以通过一下方式设置maven默认配置不仅仅对maven有效,其他默认属性同样管用方法介绍:File->OtherSettings->SettingsforNewProject①②开始设置…

    2022年9月1日
    8

发表回复

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

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