Programming Languages Hacks

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

  • Subscribe

  • Lettori

    I miei lettori abituali

  • Twitter

Archive for the 'web service' Category

Memorizzare Richieste e Risposte SOAP con le SoapExtension

Posted by Ricibald on 15th January 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?…

Posted in .net, web service | 10 Comments »

Confronto dei Metodi in .NET per Generare Proxy verso Web Service

Posted by Ricibald on 10th January 2008

Per dialogare verso un Web Service si utilizza normalmente un proxy per generare la versione “ad oggetti” delle richieste e delle risposte che dovranno viaggiare nella rete.

Tale versione ad oggetti è un rappresentante (proxy) verso la reale richiesta SOAP. Spesso quindi si parla di “proxy verso il web service”, ma solo nel significato inglese di “rappresentante”, non come riferimento verso il design pattern Proxy. In realtà, quello che viene fatto è costruire il wrapping delle richieste, il ché coincide con il design pattern Adapter.

Esistono due strumenti in .NET che consentono di creare un proxy verso il web service:

  • in Visual Studio, selezionando “add web reference”: tale metodo crea automaticamente il proxy verso il web service dichiarato
  • con il comando wsdl.exe

Viene quindi naturale cercare di capire quale metodo utilizzare, partendo dal presupposto che il primo metodo è molto più semplice e immediato. In realtà grosse differenze non ce ne sono:

  • entrambe generano classi che non dovrebbero mai essere modificate: per questo utilizzare altri approcci, come classi partial
  • entrambe possono essere customizzate:
    • in “wsdl.exe” tramite argomenti documentati qui
    • in “add web reference” configurando proprietà di “Reference.map” o creando una classe condivisa che restituisce un’istanza del proxy opportunamente configurata

Ma alcune differenze ci sono e, come è lecito aspettarsi, “wsdl.exe” è uno strumento leggermente più potente, anche se più complesso. Infatti, le seguenti personalizzazioni di wsdl.exe non trovano corrispondenza nella procedura di Visual Studio:

  • /sharetypes: consente di condividere tipi uguali utilizzati in servizi differenti (i quali altrimenti avrebbero un loro specifico proxy)
  • /server[interface]: consente di creare un servizio web service sulla base di un file wsdl. La procedura è opposta a quella utilizzata in Visual Studio, in cui quando creo un metodo si aggiorna il wsdl. L’approccio wsdl->codice è però preferibile in modo tale da mantenere l’interfaccia stabile verso i client
  • /parsableerrors: visualizza gli errori in un formato simile a quello dei compilatori
  • /order: genera identificatori di ordine espliciti

Le seguenti funzioni, viceversa, non trovano corrispondenza in “wsdl.exe”:

  • update dinamico: l’interfaccia può essere aggiornata tramite semplice click

A parte queste particolarità, i risultati prodotti sono equivalenti e quindi, a meno di esigenze specifiche come quelle elencate, consiglierei sempre di utilizzare la procedura di Visual Studio, molto più rapida.

Come al solito, non so se la mia analisi è corretta, se ci sono critiche scrivete così l’articolo verrà corretto (e imparerò dai miei errori…)

Posted in .net, web service | 31 Comments »