最佳化資料流的記憶體使用量
本主題提供使用串流模式的建議,以在傳送或接收具有 WCF 傳輸的大型訊息時,或在協調流程中載入訊息時,將訊息記憶體使用量降到最低。
在協調流程中使用程式碼來讀取訊息的內容時,請避免使用 XmlDocument 變數。 將訊息載入 XmlDocument 變數會產生大量額外負荷,特別是針對大型訊息。 此額外負荷是以記憶體使用量和處理方式來建置記憶體內部結構。 使用 XmlDocument 實例會強制將整個訊息內容載入記憶體,以建置 Document Object Module 的物件圖形 (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, transferMode = Streamed
選擇 WCF-Custom 或 WCF-CustomIsolated 配接器,以及支援 transferMode = Streamed 選項的系結,會視需要實作大型訊息串流至檔案系統,並降低潛在的記憶體不足問題。
使用串流將協調流程中載入訊息時所需的記憶體使用量降到最低
下列技術說明如何將訊息載入協調流程時,將訊息的記憶體使用量降到最低。
使用 XLANGMessage 變數來處理訊息或訊息元件的內容
將訊息從協調流程傳遞至 .NET 類別庫時,請勿將訊息當做 XmlDocument 變數傳遞,因為本主題稍早所述的原因;請改用 XLANGMessage 變數。 下列技術說明使用 XLANGMessage 變數讀取訊息或訊息元件的方法。
使用 XMLReader 處理訊息 - 若要使用 XmlReader 實例處理訊息,請將訊息以 XLANGMessage 的形式傳遞至 .NET 程式碼,並使用 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,並將 Part 內容擷取為數據流。
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 物件的實例,而不需要經過一段時間釋放它們。 如需呼叫訊息的詳細資訊。以這種方式處置 () ,請參閱BizTalk Server檔中以 XLANGMessage 表示的訊息。 本主題也提供使用 IStreamFactory 在使用者程式碼中使用串流方法建構 XLANGMessage 變數的最佳做法。
如需在協調流程所叫用協助程式元件內處理 XLANGMessage 之不同方式的詳細資訊,請參閱下列主題:
4 在協調流程第 1 部分所叫用的協助程式元件內處理 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; }