共用方式為


最佳化資料流的記憶體使用量

本主題提供使用串流模式的建議,以在傳送或接收具有 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 之不同方式的詳細資訊,請參閱下列主題:

使用 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;
    }
    

另請參閱

最佳化 BizTalk Server 應用程式