程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 《WCF技術內幕》26

《WCF技術內幕》26

編輯:關於.NET

《WCF技術內幕》26:第2部分_第5章_消息:Buffered vs Streamed、序列化和反序列化消息

Buffered vs. Streamed消息

當我們在終結點之間流動的消息時,我們會本能地想到緩存。換個方式來說 ,我們假設程序接收到一個Message時,它已經知道整個Message。這種方式稱作 緩存模式(buffering)。與之相對的就是流處理模式(streaming),並且有2種 流處理模式(streaming)。第一種是推模型(push model),發送者按照自己 的節奏推送字節流到接收者。當流數據發送的時候,發送者把數據寫到本地緩存 直到寫滿為止,數據會發生給接收者,接收者會從本地緩沖區讀取數據。第二種 機制成為拉模型(pull model)。當流數據發送的時候,接收者從發送者請求數 據,在收到請求以後,發送者發送請求的數據。這個過程會重復執行知道請求的 數據發送完畢。WCF 基礎結構實現了第二種流處理方法。

在WCF裡,Message的消息頭塊通常是緩存起來的,消息內容可以buffered或 者 streamed模式。緩存區的大小默認是64KB.(你會在第8章裡了解如何改變這 個設置。)如果消息體是streamed模式,它的大小就是無限制的。實際上,這意 味著我們可以在WCF裡傳遞流媒體。不是所有的消息都是流處理消息體元素。例 如,小的消息就不需要streamed模式;緩存模式會更加高效地處理它們。更確切 地說,一個大的消息本質上驗證是十分困難的。想一下,一個例子,假如使用 streamed模式發送一個30分鐘長的電影作為消息體的消息。電影非常不錯,並且 可以在接收完畢前就可以播放給觀眾。如果數據流終止,並且沒任何發送結束標 記,處理錯誤就變得不太可能了,因為用戶可能已經看到數據了,同樣地,如果 一個程序已經對數據做了數據簽名,這個簽名只能在整個數據流結構和緩存以後 才能驗證了,這就不適合使用streamed模式處理消息體數據。

序列化消息

既然你已經學習了如何創建消息,現在我們來研究一下如何序列化消息的全 部或者某一部分。首先,Message類型上的所有序列化方法名稱都是以Write開始 ,而且這些方法都接受XmlWriter或者XmlDictionaryWriter類型的參數。消息的 實際序列化工作由XmlWriter或者XmlDictionaryWriter對象完成,而不是直接由 Message對象完成。記得前面關於XmlDictionaryWriter的討論,實際的序列化包 括消息序列化和編碼2個步驟。序列化小的方法原型如下:

public void WriteStartEnvelope(XmlDictionaryWriter  writer);
public void WriteStartBody(XmlDictionaryWriter writer);
public void WriteStartBody(XmlWriter writer);
public void WriteBody(XmlDictionaryWriter writer);
public void WriteBody(XmlWriter writer);
public void WriteBodyContents(XmlDictionaryWriter writer);
public void WriteMessage(XmlDictionaryWriter writer);
public void WriteMessage(XmlWriter writer);

WriteMessage方法序列化消息的全部內容到XmlWriter或者 XmlDictionaryWriter包裝的Stream裡。因為這些方法序列化整個消息,因此與 其它方法相比,它們的使用頻率最高。

Message類型同樣定義了對於消息序列化進行粒度控制的方法。例如, WriteBody方法序列化body標簽和元素到XmlWriter或者XmlDictionaryWriter包 裝的Stream裡。WriteBodyContents方法,話句話說,序列化body元素(沒有 body標簽)到XmlDictionaryWriter包裝的Stream裡。WriteStartEvelope方法簡 單的寫<s:Envelope標簽到到XmlDictionaryWriter包裝的Stream裡。在 WriteStartEnvelope之後立即調用WriteStartBody方法,會寫XML namespace到 envelope,並且序列化body開始標簽,從序列化內容完全忽略消息頭。實際上, 如果我們需要在使用這些方法的時候對消息序列化做額外的控制,我們肯定想序 列化消息頭的內容。這個功能隱含在Message對象模型裡,並且會在本章後面的 “Message Headers類型”一節裡做相應的介紹。記住,如果你想手工序列化一 個消息,你必須明確序列化消息頭塊。還沒有明確的方法可以寫envelope或 body的結束標簽。但是,為了寫envelope或body的結束標簽,我們直接調用 XmlWriter. WriteEndElement方法。

反序列化消息

在接受程序裡普遍存在的一個任務就是消息的反序列化。消息的反序列化是 從一個序列化的消息創建一個新的消息的別稱。因為我們已經過了如何創建一個 Message對象,同樣也講了大部分的消息反序列化的內容。更確切地說,我們已 經學習了如何使用XmlDictionaryReader類型從一個Stream或者Byte創建一個 Message。

想一下我們關於Message工廠方法的討論,其中一種創建消息體的方法就是傳 遞Object給工廠方法。同樣的方式,我們或許需要從一個Message實例反序列化 Object。為了這個目的,Message類型定義了從Message對象反序列化消息體的成 員。這些方法的原型如下;

public T GetBody<T>();
public T GetBody<T>(XmlObjectSerializer  serializer);

泛型方法GetBody允許調用者反序列化消息體的內容到T類型的對象裡。另外 一個方法接受一個XmlObjectSerializer參數,因此為消息體的反序列化提供了 擴展點。不論我們調用哪個方法,我們必須知道Message 的消息體內包含的類型 信息。如果我們泛型方法裡使用的類型和消息體的類型不兼容,就會拋出一個 SerializationException異常。

檢查Message 是否是SOAP Fault

正如你看到的,Message類型的實例表示一個SOAP 消息或者SOAP Fault。當 接受程序反序列化一個Message的時候,它必須能夠確定這個Message是否是一個 SOAP Fault,因為通常SOAP 消息和SOAP Fault的執行路徑不同。因此,Message 定義了一個只讀屬性IsFault。簡而言之,一旦一個Message對象從進來的Stream or Byte反序列化完畢,IsFault屬性會標記Message是否是一個SOAP Fault,這 也是WCF基礎結構對於反序列化的消息作出的第一次檢查。我們可以通過改變前 面代碼裡CreateAndShowMessage方法來演示這個屬性的功能,如下所示;

private static void CreateAndShowMessage(MessageFault  messageFault,
                                           MessageVersion version) {
  Message message = Message.CreateMessage(version,
                                            messageFault,
                                            "urn:SomeFaultAction");
  // commented out for clarity
  // Console.WriteLine("{0}\n", message.ToString());

  // ** New code begins here **
  MemoryStream stream = new MemoryStream();
  // write the Message to a Stream
  XmlDictionaryWriter writer =  XmlDictionaryWriter.CreateBinaryWriter(
       stream,null, null, false);
  message.WriteMessage(writer);
  writer.Flush();

  stream.Position = 0;

  // read the Message from the Stream從Stream讀取消息
  XmlDictionaryReader reader =
       XmlDictionaryReader.CreateBinaryReader(stream, new
         XmlDictionaryReaderQuotas());
  message = Message.CreateMessage(reader, Int32.MaxValue,  version);

  // check if it is a Fault檢查消息是否是SOAP Fault
  Console.WriteLine("the message {0} a SOAP Fault",
       message.IsFault ? "is" : "is not");
}

當這些代碼執行的時候(像前面的代碼),產生下面的輸出:

the message is a SOAP Fault
the message is a SOAP Fault

注意到對於連個創建對象Message.IsFault屬性都返回true,這裡著重指出的 是對於所有的表示SOAP Fault的Message對象,Message.IsFault屬性都返回true ,不管消息數據的編碼和版本是什麼。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved