本主題提供使用串流模式的建議,以在傳送或接收具有WCF傳輸的大型訊息時,或在協調流程中載入訊息時,將訊息記憶體使用量降到最低。
使用協調流程中的程式代碼來讀取訊息的內容時,請避免使用 XmlDocument 變數。 將訊息載入 XmlDocument 變數會產生大量額外負荷,尤其是大型訊息。 此額外負荷涉及記憶體使用量和處理程序以建立記憶體中結構。 使用 XmlDocument 實例會強制將整個訊息內容載入記憶體中,以建置檔物件模組 (DOM) 的物件圖形。 這個類別實例所使用的記憶體總量,大約是實際訊息大小的10倍。 如需將訊息載入 XmlDocument 變數時所需的記憶體使用量詳細資訊,請參閱 第 9 章 – 改善 XML 效能。
本主題的其餘部分提供替代方法來讀取不需要將訊息載入 XmlDocument 變數的訊息內容。
使用 WCF 傳輸來傳送或接收大型訊息時使用串流
使用 WCF 傳輸傳送或接收大型訊息時,請使用 WCF-Custom 或 WCF-CustomIsolated 配接器,並使用支援 transferMode = Streamed 選項的系結類型進行設定,例如下列系結:
basicHttpBinding + BasicHttpBindingElement,transferMode = Streamed
netTcpBinding + NetTcpBindingElement,transferMode = Streamed
customBinding + HttpTransportElement, transferMode = Streamed
customBinding +ConnectionOrientedTransportElement,傳輸模式=串流
選擇 WCF-Custom 或 WCF-CustomIsolated 配接器,以及支援 transferMode = Streamed 選項的系結,會視需要實作大型訊息串流至文件系統,並降低潛在的記憶體不足問題。
使用串流將協調流程中載入訊息時所需的記憶體使用量降到最低
下列技術說明如何將訊息載入協調流程時,將訊息的記憶體使用量降到最低。
使用 XLANGMessage 變數來處理訊息或訊息元件的內容
將訊息從協調流程傳遞至 .NET 類別庫時,請勿以 XmlDocument 變數的形式傳遞訊息,因為本主題稍早所述的原因;請改用 XLANGMessage 變數。 下列技術說明使用 XLANGMessage 變數讀取訊息或訊息元件的方法。
使用 XMLReader 處理訊息 - 若要使用 XmlReader 實例處理訊息,請將訊息傳遞至 .NET 程式代碼做為 XLANGMessage,並使用 XmlReader 擷取 Part 內容。
public void ProcessMessage(XLANGMessage message) { try { using (XmlReader reader = message[0].RetrieveAs(typeof(XmlReader)) as XmlReader) if (reader != null) { ... } } finally { message.Dispose(); } }
使用 StreamReader 將訊息的內容擷取到字串 中 - 協調流程中 XmlDocument 的其中一個常見用法是使用 XmlDocument.OuterXml() 將訊息擷取為 XML 字符串。 下列程式代碼範例說明使用 XLANGMessage 變數將訊息擷取為字串的替代方法。
public static string MessageToString(XLANGMessage message) { string strResults; try { using (Stream stream = message[0].RetrieveAs(typeof(Stream)) as Stream) { using (StreamReader reader = new StreamReader(stream)) { strResults = reader.ReadToEnd(); } } } finally { message.Dispose(); } return strResults; }
將簡單 .NET 訊息的內容擷取到字串 中 - 如果訊息的類型是簡單的 .NET 類型,您可以將訊息擷取為該類型。 例如,若要以字串的形式取得訊息,請將訊息傳遞至 .NET 程式代碼做為 XLANGMessage,並以字串的形式擷取 Part 內容。
public void ProcessMessage(XLANGMessage message) { try { string content = message[0].RetrieveAs(typeof(string)) as string; if (!string.IsNullOrEmpty(content)) { ... } } finally { message.Dispose(); } }
將訊息的內容擷取至數據流 - 若要以數據流的形式取得訊息,請將訊息傳遞至 .NET 程式代碼做為 XLANGMessage,並將部分內容擷取為數據流。
public Stream ProcessRequestReturnStream(XLANGMessage message, int bufferSize, int thresholdSize) { ... try { using (VirtualStream virtualStream = new VirtualStream(bufferSize, thresholdSize)) { using (Stream partStream = (Stream)message[0].RetrieveAs(typeof(Stream))) //Note that when calling this code, if the XmlDocument is quite large, keeping it in a memory with a MemoryStream may have an adverse effect on performance. //In this case, it may be worthwhile to consider an approach that uses a VirtualStream + ReadonlySeekableStream to buffer it to the file system, if its size is bigger than the thresholdSize parameter. //Keep in mind that: // - If the message size is smaller than the threshold size, the VirtualStream class buffers the stream to a MemoryStream. // - If the message size is bigger than the threshold size, the VirtualStream class buffers the stream to a temporary file. using (ReadOnlySeekableStream readOnlySeekableStream = new ReadOnlySeekableStream(partStream, virtualStream, bufferSize)) { using (XmlReader reader = XmlReader.Create(readOnlySeekableStream)) { } } } } } catch (Exception ex) { } finally { message.Dispose(); } return stream; }
將訊息的內容擷取至 .NET 物件 - 若要取得訊息做為 .NET 物件,請將訊息傳遞至 .NET 程式代碼做為 XLANGMessage,並將 Part 內容擷取為 .NET 類別的實例。 使用 Visual Studio 2010 提供的 XML 架構定義工具(Xsd.exe)工具,從訊息的 Xml 架構建立後者。
備註
只有在訊息體積小時,這項技術才有效。 否則,此方法可能會導致將實際的訊息反序列化為 .NET 物件時產生大量的額外負擔。
public void ProcessMessage(XLANGMessage message) { try { Request request = message[0].RetrieveAs(typeof(Request)) as Request; if (request != null) { ... } } finally { message.Dispose(); } }
備註
在從 .NET 代碼返回之前,使用 XLANGMessage 參數所公開的 Dispose() 方法在迴圈和長時間運行的協調流程中特別重要,這些流程可能會累積 XLANGMessage 對象的實例而不隨時間釋放它們。 如需關於以這種方式呼叫 message.Dispose() 的詳細資訊,請參閱 BizTalk Server 文件中的 以 XLANGMessage 表示的訊息。 本主題也提供使用 IStreamFactory 在使用者程式代碼中使用以數據流為基礎的方法建構 XLANGMessage 變數的最佳做法。
如需協調流程所叫用之協助程式元件內處理 XLANGMessage 之不同方式的詳細資訊,請參閱下列主題:
4 在協調流程第 2 部分叫用的協助程式元件內處理 XLANGMessage 的不同方式 (開啟第三方部落格)
使用 XPathReader 和 XPathCollection 從協調流程所叫用的方法擷取 XLANGMessage 物件的值
避免使用 XMLDocument 類別從自訂程式代碼讀取 XML 訊息的內容,例如協調流程所叫用的自定義管線元件或協助程序類別。 使用 XMLDocument 實例載入 XML 訊息時,整個訊息會載入記憶體中,這效率不佳,而且可能需要最多 10 倍的實際訊息大小。 讀取 XML 訊息內容的更有效率的方式是使用串流技術,將原始數據流包裝成 Microsoft.BizTalk.Streaming.dll 元件所提供的其中一個數據流類別。 載入大型訊息時,這項技術特別有用。
如果需要從 XML 檔提取特定值,而不是使用 XmlDocument 類別公開的 SelectNodes 和 SelectSingleNode 方法,請使用 Microsoft.BizTalk.XPathReader.dll 元件所提供的 XPathReader 類別實例,如下列程式代碼範例所示。
此範例說明如何使用 XPathReader 和 XPathCollection,從協調流程所叫用之方法內的 XLANGMessage 物件擷取指定的值。
public static string SelectSingleNode(XLANGMessage message, string xPath) { try { if (message == null || string.IsNullOrEmpty(xPath)) { return string.Empty; } using (XmlReader reader = (XmlReader)message[0].RetrieveAs(typeof(XmlReader))) { XPathCollection xPathCollection = new XPathCollection(); XPathReader xPathReader = new XPathReader(reader, xPathCollection); xPathCollection.Add(xPath); while (xPathReader.ReadUntilMatch()) { if (xPathReader.Match(0)) { return xPathReader.ReadString(); } } } } catch (Exception ex) { ... } finally { message.Dispose(); } return string.Empty; }