首页 / 软件开发 / .NET编程技术 / 《WCF技术内幕》28:第2部分_第5章_消息:使用消息头(中)
《WCF技术内幕》28:第2部分_第5章_消息:使用消息头(中)2011-06-20 博客园 Frank Xu Lei译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>方法会抛出个异常。