復制消息
有時候需要從現有的一個消息實例創建一個緩存模式的消息拷貝。Message類 型定義了實現此目的的實例方法:
public MessageBuffer CreateBufferedCopy(Int32 maxBufferSize) { ... }
創建Message的拷貝還是相當簡單的,但是這會帶來消息內部狀態的改變。如 果使用不當,這個狀態改變會給我們要復制的消息對象帶來一些問題。當調用 CreateBufferedCopy方法時,新消息的state屬性必須是MessageState.Created 。如果設置為其它狀態,此方法就會拋出一個InvalidOperationException異常 。直到CreateBufferedCopy返回結果,原調用實例的狀態才會變為 MessageState.Copied。如果此方法調用成功,則會返回一個 System.ServiceModel. Channels.MessageBuffer類型的實例。MessageBuffer定 義了一個實例方法CreateMessage,它會返回一個Message類型實例。這個實例的 狀態會是Message.Created。下面代碼演示了如何復制一個消息:
Message msg = Message.CreateMessage (MessageVersion.Default,"urn:SomeAction","Something in the body");
Console.WriteLine("Starting Message state: {0}\n", msg.State);
Console.WriteLine("Message:\n{0}\n", msg.ToString());
MessageBuffer buffer = msg.CreateBufferedCopy (Int32.MaxValue);
Console.WriteLine("Message state after copy: {0}\n", msg.State);
Message msgNew = buffer.CreateMessage();
Console.WriteLine("New Message State: {0}\n",msgNew.State);
Console.WriteLine("New Message:\n{0}\n", msgNew.ToString ());
運行代碼,輸入結果如下:
Starting Message state: Created
Message:
<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>
</s:Header>
<s:Body>
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">
Something in the body</string>
</s:Body>
</s:Envelope>
Message state after copy: Copied
New Message State: Created
New Message:
<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>
</s:Header>
<s:Body>
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">
Something in the body
</string>
</s:Body>
</s:Envelope>
注意調用CreateBufferedCopy方法之後Message狀態和新的Message的狀態。 CreateBufferedCopy的作用有限,消息的狀態改變也是局限於消息復制的過程裡 。但是此功能也非常有用,在多消息參與者的場景中,像PeerChannel(對等通 道)。在PeerChannel裡,一個消息對象會被復制多次,並且這些消息拷貝會被 發送到網格裡不同節點上。
消息清理
Message類型實現了IDisposable接口,並且定義了一個Close方法。架構設計 的一個曲折之處在於,Message 實現了的Dispose成員,因此這可以阻止直接使 用Message類型。調用Dispose方法需要先把Message對象轉換為一個 IDisposable對象,然後在通過引用調用Dispose方法。更復雜是,這個曲折之處 是Close被定義為公開的方法。本質上,你調用 Message對象的Close方法,但你 不能直接調用Dispose方法。內部來講,Dispose方法調用了Close方法,所以作 用一樣,你也可以把Message的實例化放在C# using語句中。
備注:我個人認為,Message 類型對於IDisposable接口的實現有些不恰當。 我知道的所有的標准,包括Framework設計規范,規定了接口會很少會被清楚地 實現,另外也沒有那個標准接受一個Close方法,而沒有一個相似的可見的 Dispose方法。盡管這是為了避免開發人員混淆 Close/Dispose,我認為Message 使得問題更加糟糕,而不是更好。開發人員希望在類型上看到一個Dispose方法 ,有時候也希望看到 Close方法。在Microsoft .NET Framework,我還沒看到別 的類型,只暴露Close,而去隱藏掉Dispose的【老徐備注1】。
本章小結
Message類型包含的內容遠不止我們想象的那麼簡單。Message是WCF 裡一個 豐富的類型。盡管在很多WCF程序裡看不到Message類型,但是它還是存在的,並 且它是WCF通信的基本單位。因為其在WCF中的核心地位,我認為理解Message是 理解整個WCF的關鍵所在。在這一章裡,我看到多種創建Message對象的方法;如 何序列化、編碼、解碼和反序列化 Message對象;如何使用消息頭塊;等等。提 醒一下,在我們學習WCF裡不同層次的時候,重要的是要記住這些層次是相當繁 忙的,它們會在幕後完成著本章裡所描述的工作。
【老徐備注】
1.也有別的類型只暴露Close,而去隱藏掉Dispose的。但是比較少見,確實 不是一個好的設計原則。另外關於.NET垃圾回收機制,大家可以看看Jeffrey Rich的《Microsoft .NET框架程序設計(修訂版)》。