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類型
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類型
AddressHeader類型是CLR對於一個WS-Addressing參數的抽象,它簡化在序列 化之前,添加參數到Message的工作,同樣也包括反序列化之後獲取引用參數的 值。當第一次接觸AddressHeader類型的時候,可能會和MessageHeader類型
從對象模型角度來看,AddressHeader類型與Message和MessageHeader很相似 ,因為它也是一個抽象類型,並且定義了幾個工廠方法,Write 和Get 方法。( MessageHeader沒有定義Get方法。)AddressHeader類型裡的這些方法是為了與 Message 和MessageHeader保持一致性,但是不能保證重復。如果你願意的話, 我會把這些方法的實驗任務留給你。
序列化一個EndpointAddress對象
當被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
</string>
</s:Header>
<s:Body>
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">
Hello There
</string>
</s:Body>
</s:Envelope>
注意到AddressHeader 賦值給WS-Addressing終結點的FaultTo屬性。
因為WS-Addressing裡的To消息頭塊是一個xs:uri,想知道如何在至關重要的 消息頭裡使用EndpointAddress類型也很正常。正如你之前看到的, MessageHeaders的To屬性接受一個 System.Uri參數,所以我們不能使用 EndpointAddress直接設置To屬性。EndpointAddress 定義了ApplyTo實例方法來 解決這個問題。ApplyTo方法接受一個Message類型的參數,並且把 EndpointAddress的值賦值給Message,如下所示:
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");
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">
<s:Header>
<a:Action s:mustUnderstand="1">urn:SomeAction</a:Action>
<a:To s:mustUnderstand="1">http://wintellect.com/someService</a:To>
<string a:IsReferenceParameter="true"
xmlns="http://schemas.microsoft.com/203/10/Serialization/">
ref param
</string>
</s:Header>
<s:Body>
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">
Hello There
</string>
</s:Body>
</s:Envelope>
注意到EndpointAddress(包括AddressHeader)賦值給Message對象,並且每 個引用參數都符合WS-Addressing規范。