Compartir a través de


Optimización del uso de memoria con streaming

En este tema se proporcionan recomendaciones para usar patrones de streaming para minimizar las superficies de memoria de mensajes al enviar o recibir mensajes grandes con un transporte wcF o al cargar mensajes en orquestaciones.

Al usar código en una orquestación para leer el contenido de un mensaje, evite el uso de variables XmlDocument. La carga de un mensaje en una variable XmlDocument conlleva una sobrecarga significativa, especialmente para mensajes grandes. Esta sobrecarga se produce en términos de uso y procesamiento de memoria para crear las estructuras en memoria. El uso de una instancia de XmlDocument obliga a que todo el contenido del mensaje se cargue en la memoria para crear el gráfico de objetos para el módulo de objetos de documento (DOM). La cantidad total de memoria usada por una instancia de esta clase puede ser aproximadamente 10 veces el tamaño real del mensaje. Para obtener más información sobre la superficie de memoria necesaria al cargar un mensaje en una variable XmlDocument, vea capítulo 9: Mejora del rendimiento XML.

El resto de este tema proporciona métodos alternativos para leer el contenido del mensaje que no requieren cargar un mensaje en una variable XmlDocument.

Usar streaming al enviar o recibir mensajes grandes con un transporte WCF

Al enviar o recibir mensajes grandes con un transporte WCF, use el adaptador de WCF-Custom o WCF-CustomIsolated y configure con un tipo de enlace que admita la opción transferMode = Streamed , como los siguientes enlaces:

  • basicHttpBinding + BasicHttpBindingElement, transferMode = Streamed

  • netTcpBinding + NetTcpBindingElement, transferMode = Streamed

  • customBinding + HttpTransportElement, transferMode = Streamed

  • customBinding +ConnectionOrientedTransportElement, transferMode = Streamed

    Elegir un adaptador de WCF-Custom o WCF-CustomIsolated junto con un enlace que admita la opción transferMode = Streamed implementará el streaming de mensajes grandes al sistema de archivos según sea necesario y mitigará posibles problemas de memoria insuficiente.

Uso del streaming para minimizar la superficie de memoria necesaria al cargar mensajes en orquestaciones

Las técnicas siguientes describen cómo minimizar la superficie de memoria de un mensaje al cargar el mensaje en una orquestación.

Usar una variable XLANGMessage para procesar el contenido de un mensaje o elemento de mensaje

Al pasar un mensaje de una orquestación a bibliotecas de clases de .NET, no los pase como variables XmlDocument, por motivos mencionados anteriormente en este tema; en su lugar, use variables XLANGMessage. Las técnicas siguientes muestran métodos para leer un mensaje o una parte de mensaje mediante una variable XLANGMessage.

  • Procesar mensajes con XMLReader : para procesar un mensaje con una instancia xmlReader, pase el mensaje al código de .NET como un XLANGMessage y recupere el contenido del elemento mediante XmlReader.

    public void ProcessMessage(XLANGMessage message)
    {
        try
        {
            using (XmlReader reader = message[0].RetrieveAs(typeof(XmlReader)) as XmlReader)
            if (reader != null)
            {
                ...
            }
        }
        finally
        {
            message.Dispose();
        }
    }
    
  • Recuperar el contenido de un mensaje en una cadena con StreamReader : uno de los usos comunes de XmlDocument en orquestaciones es recuperar el mensaje como una cadena XML mediante XmlDocument.OuterXml(). En el ejemplo de código siguiente se muestra un método alternativo que recupera el mensaje como una cadena mediante una 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;
    }
    
  • Recuperar el contenido de mensajes de .NET simples en una cadena : si el tipo del mensaje es un tipo de .NET simple, puede recuperar el mensaje como ese tipo. Por ejemplo, para obtener el mensaje como una cadena, pase el mensaje al código de .NET como un XLANGMessage y recupere el contenido del elemento como una cadena.

    public void ProcessMessage(XLANGMessage message)
    {
        try
        {
            string content = message[0].RetrieveAs(typeof(string)) as string;
            if (!string.IsNullOrEmpty(content))
            {
                ...
            }
        }
        finally
        {
            message.Dispose();
        }
    }
    
  • Recuperar el contenido de un mensaje en una secuencia : para obtener el mensaje como una secuencia, pase el mensaje al código de .NET como un XLANGMessage y recupere el contenido del elemento como una secuencia.

    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;
    }
    
  • Recuperar el contenido de un mensaje en un objeto .NET : para obtener el mensaje como un objeto .NET, pase el mensaje al código de .NET como un XLANGMessage y recupere el contenido del elemento como una instancia de una clase .NET. Cree este último a partir del esquema Xml del mensaje mediante la herramienta Herramienta de definición de esquemas XML (Xsd.exe) proporcionada por Visual Studio 2010.

    Nota

    Esta técnica solo es válida cuando los mensajes son pequeños. De lo contrario, este enfoque podría incurrir en una sobrecarga significativa para des serializar el mensaje real en un objeto .NET.

    public void ProcessMessage(XLANGMessage message)
    {
        try
          {
          Request request = message[0].RetrieveAs(typeof(Request)) as Request;
          if (request != null)
          {
             ...
          }
       }
       finally
       {
          message.Dispose();
       }
    
    }
    

Nota

El uso del método Dispose() expuesto por el parámetro XLANGMessage antes de volver desde el código .NET es especialmente importante en escenarios de bucle y orquestaciones de larga duración que pueden acumular instancias del objeto XLANGMessage sin liberarlas con el tiempo. Para obtener más información sobre cómo llamar al mensaje. Dispose() de esta manera, consulte Mensajes representados como XLANGMessage en la documentación de BizTalk Server. En este tema también se proporcionan procedimientos recomendados para usar IStreamFactory para construir variables XLANGMessage en el código de usuario mediante un enfoque basado en secuencias.

Para obtener más información sobre las distintas formas de procesar un XLANGMessage dentro de un componente auxiliar invocado por una orquestación, vea los temas siguientes:

Usar XPathReader y XPathCollection para extraer un valor de un objeto XLANGMessage de un método invocado por una orquestación

Evite usar la clase XMLDocument para leer el contenido de los mensajes XML desde código personalizado, como componentes de canalización personalizados o clases auxiliares invocadas por orquestaciones. Cuando se usa una instancia xmlDocument para cargar un mensaje XML, todo el mensaje se carga en la memoria, lo que es ineficaz y puede requerir memoria hasta 10 veces el tamaño real del mensaje. Una manera más eficaz de leer el contenido de los mensajes XML es usar una técnica de streaming para encapsular la secuencia original con una de las clases de secuencia proporcionadas por el ensamblado Microsoft.BizTalk.Streaming.dll. Esta técnica es especialmente útil al cargar mensajes grandes.

Si es necesario extraer valores específicos de un documento XML, en lugar de usar los métodos SelectNodes y SelectSingleNode expuestos por la clase XmlDocument, use una instancia de la clase XPathReader proporcionada por el ensamblado Microsoft.BizTalk.XPathReader.dll como se muestra en el ejemplo de código siguiente.

  • En este ejemplo se muestra el uso de XPathReader y XPathCollection para extraer un valor determinado de un objeto XLANGMessage dentro de un método invocado por una orquestación.

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

Consulte también

Optimización de las aplicaciones de BizTalk Server