Programming Languages Hacks

Importanti regole per linguaggi di programmazione rilevanti come Java, C, C++, C#…

  • Subscribe

  • Lettori

    I miei lettori abituali

  • Twitter

Memorizzare Richieste e Risposte SOAP con le SoapExtension

Posted by Ricibald on January 15th, 2008

In .NET le richieste e le risposte vengono sottoposte a wrapping e serializzate nella nostra comoda struttura ad oggetti, come visto in questo precedente post. Ma a volte è necessario proprio conoscere la richiesta SOAP “nuda e cruda”. Anche se ciò che stiamo richiedendo non è niente di apparentemente complicato, la cosa si rileva però molto più complicata del previsto.

Il ciclo di vita di un web service è mostrato nella figura seguente, preso dall’articolo di Microsoft:

Ciclo di vita di un web service

Le varie fasi possono essere intercettate utilizzando le Soap Extension. Normalmente vengono utilizzate per decorare il messaggio SOAP con cifratura o compressione, ma nel nostro caso saranno semplicemente utilizzate per memorizzare le richieste e risposte SOAP.

Innanzitutto è necessario creare una classe che estende dalla classe SoapExtension:

public class MessagesPrinterSoapExtension : SoapExtension
{
    public override object GetInitializer(Type obj)
    {
        return null;
    }

    public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attr)
    {
        return null;
    }

    public override void Initialize(object initializer)
    {
    }
}

Bisogna poi implementare i seguenti metodi:

private Stream _workingStream = null;
private Stream _originalStream = null;
private static string _soapRequestMessage = null;
private static string _soapResponseMessage = null;
private SoapMessageStage? _previousStage = null;

/// <summary>
/// Allows a SOAP extension access to the memory buffer containing the SOAP request or response
/// </summary>
/// <param name="stream">A memory buffer containing the SOAP request or response.</param>
/// <returns>New memory buffer that this SOAP extension can modify</returns>
public override Stream ChainStream(Stream originalStream)
{
    _originalStream = originalStream;
    _workingStream = new MemoryStream();
    bool isResponseMessage = _previousStage != null && _previousStage == SoapMessageStage.AfterSerialize;
    if (isResponseMessage) // response message
    {
        // Get the SOAP body response as a string and copy content in a seekable stream
        _soapResponseMessage = GetMessageAndCopyStream(_originalStream, _workingStream);
    }
    return _workingStream;
}

public override void ProcessMessage(SoapMessage message)
{
    // a SOAP message has 4 stages. We're interested in AfterSerialize
    if (message.Stage == SoapMessageStage.AfterSerialize)
    {
        // Get the SOAP body request as a string and copy content in a seekable stream
        _soapRequestMessage = GetMessageAndCopyStream(_workingStream, _originalStream);
    }
    _previousStage = message.Stage;
}

Che utilizzano il metodo di utilità seguente:

/// <summary>
/// Extracts the content from input and copies it in the specified stream
/// </summary>
private static string GetMessageAndCopyStream(Stream inStream, Stream outStream)
{
    string inStreamContent;

    // If allowed, rewind
    if (inStream.CanSeek)
    {
        inStream.Position = 0;
    }

    // Read content
    StreamReader inReader = new StreamReader(inStream);
    inStreamContent = inReader.ReadToEnd();

    // Copy to output
    StreamWriter writer = new StreamWriter(outStream);
    writer.Write(inStreamContent);
    writer.Flush();

    // If allowed, rewind
    if (outStream.CanSeek)
    {
        outStream.Position = 0;
    }
    return inStreamContent;
}

Ma ora viene naturale chiedersi: come fa il mio proxy verso il web service a sapere che esisto? Semplice: basta dichiarare la classe appena creata nel file di configurazione:

<configuration>
  <system.web>
    <webServices>
      <soapExtensionTypes>
        <add type="MyNamespace.MessagesPrinterSoapExtension,MyDll" priority="1" group="Low" />
      </soapExtensionTypes>
    </webServices>
  </system.web>
</configuration>

E’ tutto! Consigli, critiche?…

Leave a Reply

You must be logged in to post a comment.