Condividi tramite


Ottimizzazione dell'utilizzo di memoria tramite flusso

In questo argomento vengono fornite raccomandazioni per l'uso di modelli di streaming per ridurre al minimo i footprint di memoria dei messaggi durante l'invio o la ricezione di messaggi di grandi dimensioni con un trasporto WCF o durante il caricamento di messaggi nelle orchestrazioni.

Quando si usa il codice in un'orchestrazione per leggere il contenuto di un messaggio, evitare di usare le variabili XmlDocument. Il caricamento di un messaggio in una variabile XmlDocument comporta un sovraccarico significativo, in particolare per i messaggi di grandi dimensioni. Questo sovraccarico è in termini di utilizzo della memoria ed elaborazione per compilare le strutture in memoria. L'uso di un'istanza di XmlDocument impone il caricamento dell'intero contenuto del messaggio in memoria per compilare il grafico dell'oggetto per il modulo dom (Document Object Module). La quantità totale di memoria usata da un'istanza di questa classe può essere circa 10 volte la dimensione effettiva del messaggio. Per altre informazioni sul footprint di memoria richiesto durante il caricamento di un messaggio in una variabile XmlDocument, vedere Capitolo 9 - Miglioramento delle prestazioni XML.

La parte restante di questo argomento fornisce metodi alternativi per la lettura del contenuto dei messaggi che non richiedono il caricamento di un messaggio in una variabile XmlDocument.

Usare lo streaming durante l'invio o la ricezione di messaggi di grandi dimensioni con un trasporto WCF

Quando si inviano o ricevono messaggi di grandi dimensioni con un trasporto WCF, usare l'adattatore WCF-Custom o WCF-CustomIsolated e configurare con un tipo di associazione che supporta l'opzione transferMode = Streamed , ad esempio le associazioni seguenti:

  • basicHttpBinding + BasicHttpBindingElement, transferMode = Streamed

  • netTcpBinding + NetTcpBindingElement, transferMode = Streamed

  • customBinding + HttpTransportElement, transferMode = Streamed

  • customBinding +ConnectionOrientedTransportElement, transferMode = Streamed

    La scelta di una scheda WCF-Custom o WCF-CustomIsolated insieme a un'associazione che supporta l'opzione transferMode = Streamed implementerà lo streaming di messaggi di grandi dimensioni nel file system in base alle esigenze e ridurrà i potenziali problemi di memoria insufficiente.

Usare lo streaming per ridurre al minimo il footprint di memoria richiesto durante il caricamento dei messaggi nelle orchestrazioni

Le tecniche seguenti descrivono come ridurre al minimo il footprint di memoria di un messaggio durante il caricamento del messaggio in un'orchestrazione.

Usare una variabile XLANGMessage per elaborare il contenuto di un messaggio o di una parte del messaggio

Quando si passa un messaggio da un'orchestrazione alle librerie di classi .NET, non passarle come variabili XmlDocument, per motivi menzionati in precedenza in questo argomento; usare invece variabili XLANGMessage. Le tecniche seguenti illustrano i metodi per la lettura di un messaggio o una parte di messaggio usando una variabile XLANGMessage.

  • Elaborare i messaggi con XMLReader : per elaborare un messaggio con un'istanza di XmlReader, passare il messaggio al codice .NET come XLANGMessage e recuperare il contenuto della parte usando XmlReader.

    public void ProcessMessage(XLANGMessage message)
    {
        try
        {
            using (XmlReader reader = message[0].RetrieveAs(typeof(XmlReader)) as XmlReader)
            if (reader != null)
            {
                ...
            }
        }
        finally
        {
            message.Dispose();
        }
    }
    
  • Recuperare il contenuto di un messaggio in una stringa con StreamReader : uno degli usi comuni di XmlDocument nelle orchestrazioni consiste nel recuperare il messaggio come stringa XML usando XmlDocument.OuterXml(). Nell'esempio di codice seguente viene illustrato un metodo alternativo che recupera il messaggio come stringa usando una variabile 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;
    }
    
  • Recuperare il contenuto di messaggi .NET semplici in una stringa : se il tipo del messaggio è un tipo .NET semplice, è possibile recuperare il messaggio come tale tipo. Ad esempio, per ottenere il messaggio come stringa, passare il messaggio al codice .NET come XLANGMessage e recuperare il contenuto della parte come stringa.

    public void ProcessMessage(XLANGMessage message)
    {
        try
        {
            string content = message[0].RetrieveAs(typeof(string)) as string;
            if (!string.IsNullOrEmpty(content))
            {
                ...
            }
        }
        finally
        {
            message.Dispose();
        }
    }
    
  • Recuperare il contenuto di un messaggio in un flusso : per ottenere il messaggio come flusso, passare il messaggio al codice .NET come XLANGMessage e recuperare il contenuto della parte come flusso.

    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;
    }
    
  • Recuperare il contenuto di un messaggio in un oggetto .NET : per ottenere il messaggio come oggetto .NET, passare il messaggio al codice .NET come XLANGMessage e recuperare il contenuto della parte come istanza di una classe .NET. Creare quest'ultimo da Xml Schema del messaggio usando lo strumento xml Schema Definition Tool (Xsd.exe) fornito da Visual Studio 2010.

    Nota

    Questa tecnica è valida solo quando i messaggi sono piccoli. In caso contrario, questo approccio potrebbe comportare un sovraccarico significativo per de-serializzare il messaggio effettivo in un oggetto .NET.

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

Nota

L'uso del metodo Dispose() esposto dal parametro XLANGMessage prima di restituire dal codice .NET è particolarmente importante negli scenari di ciclo e nelle orchestrazioni a esecuzione prolungata che possono accumulare istanze dell'oggetto XLANGMessage senza rilasciarli nel tempo. Per altre informazioni sulla chiamata al messaggio. Dispose() in questo modo, vedere Messaggi rappresentati come XLANGMessage nella documentazione di BizTalk Server. Questo argomento fornisce anche procedure consigliate per l'uso di IStreamFactory per costruire variabili XLANGMessage nel codice utente usando un approccio basato su flusso.

Per altre informazioni sui diversi modi per elaborare un XLANGMessage all'interno di un componente helper richiamato da un'orchestrazione, vedere gli argomenti seguenti:

Uso di XPathReader e XPathCollection per estrarre un valore da un oggetto XLANGMessage da un metodo richiamato da un'orchestrazione

Evitare di usare la classe XMLDocument per leggere il contenuto dei messaggi XML dal codice personalizzato, ad esempio componenti della pipeline personalizzati o classi helper richiamate da orchestrazioni. Quando si usa un'istanza XMLDocument per caricare un messaggio XML, l'intero messaggio viene caricato in memoria, che è inefficiente e può richiedere memoria fino a 10 volte la dimensione effettiva del messaggio. Un modo più efficiente per leggere il contenuto dei messaggi XML consiste nell'usare una tecnica di streaming per eseguire il wrapping del flusso originale con una delle classi di flusso fornite dall'assembly Microsoft.BizTalk.Streaming.dll. Questa tecnica è particolarmente utile quando si caricano messaggi di grandi dimensioni.

Se è necessario eseguire il pull di valori specifici da un documento XML, anziché usare i metodi SelectNodes e SelectSingleNode esposti dalla classe XmlDocument, usare un'istanza della classe XPathReader fornita dall'assembly Microsoft.BizTalk.XPathReader.dll come illustrato nell'esempio di codice seguente.

  • Questo esempio illustra l'uso di XPathReader e XPathCollection per estrarre un determinato valore da un oggetto XLANGMessage all'interno di un metodo richiamato da un'orchestrazione.

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

Vedere anche

Ottimizzazione delle applicazioni BizTalk Server