Optimieren der Speicherauslastung mithilfe von Streaming
Dieses Thema enthält Empfehlungen für die Verwendung von Streamingmustern zum Minimieren des Nachrichtenspeicherbedarfs beim Senden oder Empfangen großer Nachrichten mit einem WCF-Transport oder beim Laden von Nachrichten in Orchestrierungen.
Wenn Sie Code in einer Orchestrierung verwenden, um den Inhalt einer Nachricht zu lesen, vermeiden Sie die Verwendung von XmlDocument-Variablen. Das Laden einer Nachricht in eine XmlDocument-Variable verursacht einen erheblichen Mehraufwand, insbesondere bei großen Nachrichten. Dieser Mehraufwand bezieht sich auf die Speicherauslastung und -verarbeitung, um die In-Memory-Strukturen zu erstellen. Die Verwendung eines XmlDocument-instance erzwingt, dass der gesamte Nachrichteninhalt in den Arbeitsspeicher geladen wird, um das Objektdiagramm für das Document Object Module (DOM) zu erstellen. Die von einem instance dieser Klasse verwendete Gesamtspeichermenge kann etwa das 10-fache der tatsächlichen Nachrichtengröße betragen. Weitere Informationen zum erforderlichen Speicherbedarf beim Laden einer Nachricht in eine XmlDocument-Variable finden Sie unter Kapitel 9 – Verbessern der XML-Leistung.
Im weiteren Verlauf dieses Themas finden Sie alternative Methoden zum Lesen von Nachrichteninhalten, für die keine Nachricht in eine XmlDocument-Variable geladen werden muss.
Verwenden von Streaming beim Senden oder Empfangen großer Nachrichten mit einem WCF-Transport
Verwenden Sie beim Senden oder Empfangen großer Nachrichten mit einem WCF-Transport den WCF-Custom- oder WCF-CustomIsolated adapter, und konfigurieren Sie mit einem Bindungstyp, der die Option transferMode = Streamed unterstützt, z. B. die folgenden Bindungen:
basicHttpBinding + BasicHttpBindingElement, transferMode = Streamed
netTcpBinding + NetTcpBindingElement, transferMode = Streamed
customBinding + HttpTransportElement, transferMode = Streamed
customBinding +ConnectionOrientedTransportElement, transferMode = Streamed
Wenn Sie einen WCF-Custom- oder WCF-CustomIsolated-Adapter zusammen mit einer Bindung auswählen, die die Option transferMode = Streamed unterstützt, wird das Streaming großer Nachrichten an das Dateisystem nach Bedarf implementiert und potenzielle Probleme mit nicht genügend Arbeitsspeicher vermieden.
Verwenden von Streaming zur Minimierung des Speicherbedarfs, der beim Laden von Nachrichten in Orchestrierungen erforderlich ist
Die folgenden Techniken beschreiben, wie Sie den Speicherbedarf einer Nachricht beim Laden der Nachricht in eine Orchestrierung minimieren.
Verwenden einer XLANGMessage-Variablen zum Verarbeiten des Inhalts einer Nachricht oder eines Nachrichtenteils
Wenn Sie eine Nachricht aus einer Orchestrierung an .NET-Klassenbibliotheken übergeben, übergeben Sie diese aus den weiter oben in diesem Thema erwähnten Gründen nicht als XmlDocument-Variablen. Verwenden Sie stattdessen XLANGMessage-Variablen. Die folgenden Techniken veranschaulichen Methoden zum Lesen einer Nachricht oder eines Nachrichtenteils mithilfe einer XLANGMessage-Variablen.
Verarbeiten von Nachrichten mit XMLReader: Um eine Nachricht mit einem XmlReader-instance zu verarbeiten, übergeben Sie die Nachricht als XLANGMessage an .NET-Code, und rufen Sie den Teilinhalt mithilfe von XmlReader ab.
public void ProcessMessage(XLANGMessage message) { try { using (XmlReader reader = message[0].RetrieveAs(typeof(XmlReader)) as XmlReader) if (reader != null) { ... } } finally { message.Dispose(); } }
Abrufen des Inhalts einer Nachricht in eine Zeichenfolge mit StreamReader : Eine der gängigen Verwendungen von XmlDocument in Orchestrierungen besteht darin, die Nachricht mithilfe von XmlDocument.OuterXml() als XML-Zeichenfolge abzurufen. Das folgende Codebeispiel veranschaulicht eine alternative Methode, die die Nachricht mithilfe einer XLANGMessage-Variablen als Zeichenfolge abruft.
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; }
Abrufen des Inhalts einfacher .NET-Nachrichten in einer Zeichenfolge : Wenn der Typ der Nachricht ein einfacher .NET-Typ ist, können Sie die Nachricht als diesen Typ abrufen. Um die Nachricht beispielsweise als Zeichenfolge abzurufen, übergeben Sie die Nachricht als XLANGMessage an den .NET-Code, und rufen Sie den Teilinhalt als Zeichenfolge ab.
public void ProcessMessage(XLANGMessage message) { try { string content = message[0].RetrieveAs(typeof(string)) as string; if (!string.IsNullOrEmpty(content)) { ... } } finally { message.Dispose(); } }
Abrufen des Inhalts einer Nachricht in einen Stream : Um die Nachricht als Datenstrom abzurufen, übergeben Sie die Nachricht als XLANGMessage an den .NET-Code, und rufen Sie den Teilinhalt als Stream ab.
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; }
Abrufen des Inhalts einer Nachricht in ein .NET-Objekt: Um die Nachricht als .NET-Objekt abzurufen, übergeben Sie die Nachricht als XLANGMessage an den .NET-Code, und rufen Sie den Part-Inhalt als instance einer .NET-Klasse ab. Erstellen Sie letzteres anhand des XML-Schemas der Nachricht mithilfe des von Visual Studio 2010 bereitgestellten XML-Schemadefinitionstools (Xsd.exe).
Hinweis
Diese Technik ist nur gültig, wenn Nachrichten klein sind. Andernfalls könnte dieser Ansatz einen erheblichen Mehraufwand verursachen, um die eigentliche Nachricht in ein .NET-Objekt zu deserialisieren.
public void ProcessMessage(XLANGMessage message) { try { Request request = message[0].RetrieveAs(typeof(Request)) as Request; if (request != null) { ... } } finally { message.Dispose(); } }
Hinweis
Die Verwendung der Dispose() -Methode, die vom XLANGMessage-Parameter vor der Rückgabe aus dem .NET-Code verfügbar gemacht wird, ist besonders wichtig in Schleifenszenarien und Orchestrierungen mit langer Ausführungszeit, die Instanzen des XLANGMessage-Objekts akkumulieren können, ohne sie im Laufe der Zeit freizugeben. Weitere Informationen zum Aufrufen einer Nachricht. Dispose() auf diese Weise finden Sie in der Dokumentation zu BizTalk Server unter Als XLANGMessage dargestellte Nachrichten. Dieses Thema enthält auch bewährte Methoden für die Verwendung von IStreamFactory zum Erstellen von XLANGMessage-Variablen im Benutzercode mithilfe eines streambasierten Ansatzes.
Weitere Informationen zu den verschiedenen Möglichkeiten zum Verarbeiten einer XLANGMessage in einer Hilfskomponente, die von einer Orchestrierung aufgerufen wird, finden Sie in den folgenden Themen:
4 Verschiedene Möglichkeiten zum Verarbeiten einer XLANGMessage in einer Hilfskomponente, die von einer Orchestrierung aufgerufen wird, Teil 1 (öffnet den Blog eines Drittanbieters)
4 Verschiedene Möglichkeiten zum Verarbeiten einer XLANGMessage in einer Hilfskomponente, die von einer Orchestrierung aufgerufen wird, Teil 2 (öffnet den Blog eines Drittanbieters)
Verwenden von XPathReader und XPathCollection zum Extrahieren eines Werts aus einem XLANGMessage-Objekt aus einer Methode, die von einer Orchestrierung aufgerufen wird
Vermeiden Sie die Verwendung der XMLDocument-Klasse, um den Inhalt von XML-Nachrichten aus benutzerdefiniertem Code zu lesen, z. B. benutzerdefinierte Pipelinekomponenten oder Hilfsklassen, die von Orchestrierungen aufgerufen werden. Wenn Sie eine XMLDocument-instance zum Laden einer XML-Nachricht verwenden, wird die gesamte Nachricht in den Arbeitsspeicher geladen, was ineffizient ist und bis zu 10 Mal mehr Arbeitsspeicher benötigt als die tatsächliche Größe der Nachricht. Eine effizientere Möglichkeit zum Lesen des Inhalts von XML-Nachrichten ist die Verwendung einer Streamingtechnik zum Umschließen des ursprünglichen Datenstroms mit einer der stream-Klassen, die von der Microsoft.BizTalk.Streaming.dll-Assembly bereitgestellt werden. Diese Technik ist besonders nützlich beim Laden großer Nachrichten.
Wenn bestimmte Werte aus einem XML-Dokument abgerufen werden müssen, verwenden Sie anstelle der SelectNodes- und SelectSingleNode-Methoden, die von der XmlDocument-Klasse verfügbar gemacht werden, eine instance der XPathReader-Klasse, die von der Microsoft.BizTalk.XPathReader.dll Assembly bereitgestellt wird, wie im folgenden Codebeispiel veranschaulicht.
Dieses Beispiel veranschaulicht die Verwendung von XPathReader und XPathCollection, um einen bestimmten Wert aus einem XLANGMessage-Objekt in einer Methode zu extrahieren, die von einer Orchestrierung aufgerufen wird.
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; }