Optimisation de l’utilisation de la mémoire avec le streaming
Cette rubrique fournit des recommandations pour l’utilisation de modèles de diffusion en continu afin de réduire l’encombrement de la mémoire des messages lors de l’envoi ou de la réception de messages volumineux avec un transport WCF ou lors du chargement de messages dans des orchestrations.
Lorsque vous utilisez du code dans une orchestration pour lire le contenu d’un message, évitez d’utiliser des variables XmlDocument. Le chargement d’un message dans une variable XmlDocument entraîne une surcharge importante, en particulier pour les messages volumineux. Cette surcharge est liée à l’utilisation de la mémoire et au traitement pour créer les structures en mémoire. L’utilisation d’un instance XmlDocument force le chargement en mémoire de tout le contenu du message afin de générer le graphique d’objets pour le module DOM (Document Object Module). La quantité totale de mémoire utilisée par un instance de cette classe peut être d’environ 10 fois la taille réelle du message. Pour plus d’informations sur l’empreinte mémoire requise lors du chargement d’un message dans une variable XmlDocument, consultez Chapitre 9 : Amélioration des performances XML.
Le reste de cette rubrique fournit d’autres méthodes pour lire le contenu des messages qui ne nécessitent pas le chargement d’un message dans une variable XmlDocument.
Utiliser la diffusion en continu lors de l’envoi ou de la réception de messages volumineux avec un transport WCF
Lors de l’envoi ou de la réception de messages volumineux avec un transport WCF, utilisez l’adaptateur WCF-Custom ou WCF-CustomIsolated et configurez avec un type de liaison qui prend en charge l’option transferMode = Streamed , comme les liaisons suivantes :
basicHttpBinding + BasicHttpBindingElement, transferMode = Streamed
netTcpBinding + NetTcpBindingElement, transferMode = Streamed
customBinding + HttpTransportElement, transferMode = Streamed
customBinding +ConnectionOrientedTransportElement, transferMode = Streamed
Le choix d’une carte WCF-Custom ou WCF-CustomIsolated, ainsi qu’une liaison qui prend en charge l’option transferMode = Streamed , implémente la diffusion en continu de messages volumineux vers le système de fichiers en fonction des besoins et atténue les éventuels problèmes de mémoire insuffisante.
Utiliser la diffusion en continu pour réduire l’empreinte mémoire requise lors du chargement des messages dans des orchestrations
Les techniques suivantes décrivent comment réduire l’empreinte mémoire d’un message lors du chargement du message dans une orchestration.
Utiliser une variable XLANGMessage pour traiter le contenu d’un message ou d’une partie de message
Lorsque vous transmettez un message d’une orchestration à des bibliothèques de classes .NET, ne les transmettez pas en tant que variables XmlDocument, pour les raisons mentionnées plus haut dans cette rubrique ; utilisez plutôt des variables XLANGMessage. Les techniques suivantes illustrent les méthodes de lecture d’un message ou d’une partie de message à l’aide d’une variable XLANGMessage.
Traiter des messages avec XMLReader : pour traiter un message avec un instance XmlReader, transmettez le message au code .NET en tant que XLANGMessage et récupérez le contenu du composant à l’aide de XmlReader.
public void ProcessMessage(XLANGMessage message) { try { using (XmlReader reader = message[0].RetrieveAs(typeof(XmlReader)) as XmlReader) if (reader != null) { ... } } finally { message.Dispose(); } }
Récupérer le contenu d’un message dans une chaîne avec StreamReader : l’une des utilisations courantes de XmlDocument dans les orchestrations consiste à récupérer le message sous forme de chaîne XML à l’aide de XmlDocument.OuterXml(). L’exemple de code suivant illustre une autre méthode qui récupère le message sous forme de chaîne à l’aide d’une variable 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; }
Récupérer le contenu des messages .NET simples dans une chaîne : si le type du message est un type .NET simple, vous pouvez récupérer le message comme ce type. Par exemple, pour obtenir le message sous forme de chaîne, transmettez le message au code .NET en tant que XLANGMessage et récupérez le contenu du composant sous forme de chaîne.
public void ProcessMessage(XLANGMessage message) { try { string content = message[0].RetrieveAs(typeof(string)) as string; if (!string.IsNullOrEmpty(content)) { ... } } finally { message.Dispose(); } }
Récupérer le contenu d’un message dans un flux : pour obtenir le message en tant que flux, transmettez le message au code .NET en tant que XLANGMessage et récupérez le contenu du composant en tant que flux.
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; }
Récupérer le contenu d’un message dans un objet .NET : pour obtenir le message sous la forme d’un objet .NET, transmettez le message au code .NET en tant que XLANGMessage et récupérez le contenu part en tant que instance d’une classe .NET. Créez ce dernier à partir du schéma XML du message à l’aide de l’outil de définition de schéma XML (Xsd.exe) fourni par Visual Studio 2010.
Notes
Cette technique n’est valide que lorsque les messages sont petits. Sinon, cette approche pourrait entraîner une surcharge importante pour dé sérialiser le message réel dans un objet .NET.
public void ProcessMessage(XLANGMessage message) { try { Request request = message[0].RetrieveAs(typeof(Request)) as Request; if (request != null) { ... } } finally { message.Dispose(); } }
Notes
L’utilisation de la méthode Dispose() exposée par le paramètre XLANGMessage avant le retour à partir du code .NET est particulièrement importante dans les scénarios de boucle et les orchestrations à long terme qui peuvent accumuler des instances de l’objet XLANGMessage sans les libérer au fil du temps. Pour plus d’informations sur l’appel de message. Dispose() de cette manière, consultez Messages représentés en tant que XLANGMessage dans la documentation BizTalk Server. Cette rubrique fournit également les meilleures pratiques pour l’utilisation d’IStreamFactory pour construire des variables XLANGMessage dans le code utilisateur à l’aide d’une approche basée sur le flux.
Pour plus d’informations sur les différentes façons de traiter un XLANGMessage au sein d’un composant d’assistance appelé par une orchestration, consultez les rubriques suivantes :
4 Différentes façons de traiter un XLANGMessage au sein d’un composant d’assistance appelé par une orchestration Partie 1 (ouvre le blog tiers)
4 Différentes façons de traiter un XLANGMessage au sein d’un composant d’assistance appelé par une orchestration Partie 2 (ouvre le blog tiers)
Utilisation de XPathReader et XPathCollection pour extraire une valeur d’un objet XLANGMessage d’une méthode appelée par une orchestration
Évitez d’utiliser la classe XMLDocument pour lire le contenu des messages XML à partir de code personnalisé, tels que des composants de pipeline personnalisés ou des classes d’assistance appelées par des orchestrations. Lorsque vous utilisez un instance XMLDocument pour charger un message XML, l’ensemble du message est chargé en mémoire, ce qui est inefficace et peut nécessiter une mémoire jusqu’à 10 fois la taille réelle du message. Un moyen plus efficace de lire le contenu des messages XML consiste à utiliser une technique de diffusion en continu pour encapsuler le flux d’origine avec l’une des classes de flux fournies par l’assembly Microsoft.BizTalk.Streaming.dll. Cette technique est particulièrement utile lors du chargement de messages volumineux.
Si des valeurs spécifiques doivent être extraites d’un document XML, au lieu d’utiliser les méthodes SelectNodes et SelectSingleNode exposées par la classe XmlDocument, utilisez une instance de la classe XPathReader fournie par l’assembly Microsoft.BizTalk.XPathReader.dll, comme illustré dans l’exemple de code suivant.
Cet exemple illustre l’utilisation de XPathReader et XPathCollection pour extraire une valeur donnée d’un objet XLANGMessage à l’intérieur d’une méthode appelée par une orchestration.
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; }