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


相关推荐

  • python skitlearn_Python sklearn

    python skitlearn_Python sklearn1.Sklearn简介Scikit-learn(sklearn)是机器学习中常用的第三方模块,对常用的机器学习方法进行了封装,包括回归(Regression)、降维(DimensionalityReduction)、分类(Classfication)、聚类(Clustering)等方法。当我们面临机器学习问题时,便可根据下图来选择相应的方法。Sklearn具有以下特点:简单高效的数据挖…

    2022年8月31日
    0
  • 记使用 git clean -d -fx ” ” 命令(建议慎用)[通俗易懂]

    记使用 git clean -d -fx ” ” 命令(建议慎用)

    2022年2月10日
    49
  • mysql卸载步骤_系统应用怎么卸载步骤

    mysql卸载步骤_系统应用怎么卸载步骤重装卸载了一下午,很多方法都尝试了,最后终于找到一个彻底删干净的方法:1.很多大佬都提到的cmd搜索regedit注册表,打开后找到下面三个目录并删除(要是没有不用管)HKEY_LOCAL_MACHINE/SYSTEM/ControlSet001/Services/Eventlog/Application/MySQLHKEY_LOCAL_MACHINE/SYSTEM/ControlSet002/Services/Eventlog/Application/MySQLHKEY_LOCAL_MACHIN

    2022年9月27日
    0
  • 数据库sql嵌套查询题_sql子查询嵌套优化

    数据库sql嵌套查询题_sql子查询嵌套优化一、嵌套查询概念在sql语言中,一个select-from-where语句成为一个查询块,将一个查询块嵌套在另一个查询块的where子句或having短语的条件中的查询成为嵌套查询。外层的查询块称为外层查询或父查询,内层的查询称为内层查询或子查询。注意点:子查询的select语句不能使用orderby子句,orderby只能对最终查询结果排序。嵌套查询分类:1、相关子查询/关联子查询:子查询的查询条件依赖于父查询,比如,如果子查询需要执行多次,即采用循环的方式,先从外部查询开始,每

    2022年8月10日
    3
  • 不止一个背包的背包问题_超级背包怎么使用方法

    不止一个背包的背包问题_超级背包怎么使用方法有 N 个物品和一个容量是 V 的背包。物品之间具有依赖关系,且依赖关系组成一棵树的形状。如果选择一个物品,则必须选择它的父节点。如下图所示:如果选择物品5,则必须选择物品1和2。这是因为2是5的父节点,1是2的父节点。每件物品的编号是 i,体积是 vi,价值是 wi,依赖的父节点编号是 pi。物品的下标范围是 1…N。求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。输出最大价值。输入格式第一行有两个整数 N,V,用空格隔开,分别表示物品个数和背包容量。接下来有 N

    2022年8月9日
    3
  • 利用DOSBox运行汇编超详细步骤「建议收藏」

    利用DOSBox运行汇编超详细步骤「建议收藏」最近学校要求用汇编写课设,笔试取消,无奈只有配置环境自己写课设了。起初是利用VS2017进行配置,但后面运行好像有些问题,就想到用DOSBox了。

    2022年6月15日
    30

发表回复

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

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