天天看点

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

WS-Addressing 和MessageHeaders类型

在前面“MessageHeader类型”一节,我们已经学习了使用MessageHeader表一个WS-Addressing终结点。我们会很少手动编写代码来使用一个MessageHeader去表示WS-Addressing终结点,因为MessageHeaders类型定义了几个表示一个终结点引用的属性。换句话说,MessageHeaders定义了几个可以增加、修改和删除WS-Addressing消息头块的方法,并且这个是给Message实例设置消息头块的主要方法。

更确切地说,MessageHeaders类型定义了以下与终结点相关的属性:From, ReplyTo, FaultTo, and To。From、ReplyTo和FaultTo是EndpointAddress的属性。如前面提到的一样,EndpointAddress类型是对于WS-Addressing 终结点规范定义的CLR抽象。我们会在下一节里详细学习EndpointAddress类型。根据WS-Addressing规范里的定义,To是Uri类型的属性。

MessageHeaders类型同样定义了与其它WS-Addressing规范相关的属性。例如,Action、MessageId和RelatesTo属性映射到相似名字的WS-Addressing消息头块上。Action是String类型,而且非常简单。概括地说,当属性设置完毕,WS-Addressing Action也会在Message序列化的时候序列化。

MessageId和RelatesTo属性是UniqueId类型的,而且也很简单。UniqueId类型很像GUID,但是它借助重载的构造函数,可以使用其它类型。思考下面的代码:

UniqueId uniqueId = new UniqueId(); 

Console.WriteLine(uniqueId.ToString()); 

uniqueId = new UniqueId("myuniquevalue"); 

Console.WriteLine(uniqueId.ToString());

运行代码,产生以下输出:

urn:uuid:

myuniquevalue

注意UniqueId对象的值可以是GUID类型的值,也可以是任意String的值。这是个必要的功能,因为MessageId 和RelatesTo  WS-Addressing消息头块是xs:Uri类型。换句话说,任何值都可以在这里替换。因为WCF遵循WS-Addressing规范,System.Guid不能表示这些属性。

EndpointAddress类型由两个功能:它可以方便地保存目标地址的信息,并且它是一个序列化WS-Addressing终结点到Message里的方式。换句换说,EndpointAddress类型是经常使用的API之一,但是它同样在Message序列化和反序列化里起着重要作用。

EndpointAddress包装了一个System.Uri对象。因此,所有的EndpointAddress构造函数某些形式上,都接受一个System.Uri参数。更进一步说,6个构造函数里有5个接受一个Uri参数,另外一个接受String参数。但是这个构造函数会从此String参数来构造一个Uri然后调用其它的一个构造函数。EndpointAddress这个特性使得类型更加好用,如下所示:

EndpointAddress address1 = new

EndpointAddress("http://wintellect.com/OrderStuff");

Console.WriteLine("Address1: {0}",address1.ToString());

EndpointAddress address2 = new EndpointAddress(

new Uri("http://wintellect.com/OrderStuff"));

Console.WriteLine("Address2: {0}", address2.ToString());

Console.WriteLine("address1 {0} address2",

(address1 == address2) ? "equals" : "does not equal");

Address1: http://wintellect.com/OrderStuff

Address2: http://wintellect.com/OrderStuff

Address1 equals Address2

注意到ToString方法返回是Uri的String形式,而不是一个序列化的EndpointAddress。同样也看到2个构造函数创建了等价的EndpointAddress对象。(在EndpointAddress类型上的重载操作符为了相等性检查对象的内部状态。)

还有几个其它的重载构造函数接受一个AddressHeader、AddressHeaderCollection、EndpointIdentity和 XmlDictionaryReader类型的参数。最值得注意的是AddressHeader类型的参数,而这个就是我们接下来的内容。

AddressHeader类型是CLR对于一个WS-Addressing参数的抽象,它简化在序列化之前,添加参数到Message的工作,同样也包括反序列化之后获取引用参数的值。当第一次接触AddressHeader类型的时候,可能会和MessageHeader类型

从对象模型角度来看,AddressHeader类型与Message和MessageHeader很相似,因为它也是一个抽象类型,并且定义了几个工厂方法,Write 和Get 方法。(MessageHeader没有定义Get方法。)AddressHeader类型里的这些方法是为了与Message 和MessageHeader保持一致性,但是不能保证重复。如果你愿意的话,我会把这些方法的实验任务留给你。

当被Message 对象引用的时候,EndpointAddress非常有用。这经常是通过Message类型的Headers属性来完成。比如,我们可以实例化一个EndpointAddress并且赋值给Message的FaultTo属性。例如:

String uriValue = "http://wintellect.com/someService"; 

AddressHeader header = AddressHeader.CreateAddressHeader("ref param"); 

EndpointAddress address = new EndpointAddress(new Uri(uriValue), 

new AddressHeader[1] { header }); // notice the use of the AddressHeader 

Message myMessage = Message.CreateMessage( 

MessageVersion.Soap12WSAddressing10, "urn:SomeAction", "Hello There"); 

myMessage.Headers.FaultTo = address; 

Console.WriteLine(myMessage.ToString());

<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:SomeAction</a:Action> 

        <a:FaultTo> 

            <a:Address>http://wintellect.com/someService</a:Address> 

            <a:ReferenceParameters> 

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

                 ref param 

             </string> 

            </a:ReferenceParameters> 

        </a:FaultTo> 

</s:Header> 

<s:Body> 

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

            Hello There 

        </string> 

</s:Body> 

</s:Envelope> 

        <string a:IsReferenceParameter="true" 

                        xmlns="http://schemas.microsoft.com/203/10/Serialization/"> 

            ref param 

注意到AddressHeader 赋值给WS-Addressing终结点的FaultTo属性。 

因为WS-Addressing里的To消息头块是一个xs:uri,想知道如何在至关重要的消息头里使用EndpointAddress类型也很正常。正如你之前看到的,MessageHeaders的To属性接受一个System.Uri参数,所以我们不能使用EndpointAddress直接设置To属性。EndpointAddress 定义了ApplyTo实例方法来解决这个问题。ApplyTo方法接受一个Message类型的参数,并且把EndpointAddress的值赋值给Message,如下所示: 

address.ApplyTo(myMessage); 

Console.WriteLine(myMessage); 

运行代码,产生以下输出: 

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

xmlns:s="http://www.3.org/2003/05/soap-envelope"> 

        <a:To s:mustUnderstand="1">http://wintellect.com/someService</a:To> 

</s:Envelope>

注意到EndpointAddress(包括AddressHeader)赋值给Message对象,并且每个引用参数都符合WS-Addressing规范。

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

继续阅读