Web Services, Remoting, WSE2: pregi e difetti

4 pagine in totale: <<Indietro 1 [2] 3 4 Avanti >>

Remoting

La tecnica utilizzata dal remoting è pressappoco simile a quella precedente: trasformazione del file in un array di byte ed invio vero e proprio. L'implementazione è ovviamente diversa. Quando vogliamo registrare un web service in una nostra web application è sufficiente l'aggiunta di una web references direttamente dall'ambiente di lavoro o l'utilizzo del comando "wsdl.exe" dal prompt.

Con il remoting l'approccio è diverso ed anche se non entriamo nel merito (non basterebbe un articolo), possiamo semplificare il discorso dicendo che per richiamare una classe e le funzioni su un pc remoto, dobbiamo avere la stessa classe, o per meglio dire, una classe con la stessa signature sia nell'applicazione chiamante che quella che riceverà la richiesta. Via codice possiamo risolvere agevolmente il tutto con l'uso di un'interfaccia comune per entrambe le applicazioni, anche se questo complica leggermente la procedura per l'istanziamento della classe:

public interface IInterfacciaUpload
{
   bool File(byte[] Contenuto, string NomeFile);
}

Ed ecco il codice eseguito quando l'utente selezionerà l'upload del file con il remoting:

private void Button2_Click(object sender, System.EventArgs e)
{
   try
   {
      int lunghezza = xfile.PostedFile.ContentLength;
      if (lunghezza > 0)
      {
         byte[] b=new  byte[lunghezza];
         xfile.PostedFile.InputStream.Read(b,0,lunghezza);
         string nomefile= Path.GetFileName(xfile.PostedFile.FileName);

         IInterfacciaUpload remot;
         string location = "tcp://127.0.0.1:1980/RemotingUpload";
         remot = (IInterfacciaUpload)Activator.GetObject(
            typeof(IInterfacciaUpload), location);
         if (remot.File(b, nomefile))
            Label1.Text = "ok!";
         else
            Label1.Text = "NOOO!";
      }
      else
         Label1.Text = "Nessun file!";
     }
     catch (Exception ex)
     {
        Label1.Text = ex.ToString();
     }
}

Se invece dell'uso dell'interfaccia comune avessimo utilizzato una classe, avremmo dovuto condividerla tra le due applicazioni. Questo ci avrebbe consentito una procedura più classica per l'istanziamento della classe:

string location = "tcp://127.0.0.1:1980/RemotingUpload";
RemotingConfiguration.RegisterWellKnowClientType(
   typeof(RemotingUpload),
   location);
RemotingUpload remot=new RemotingUpload();
if (remot.File(b, nomefile))
...

Nello stesso progetto dovremo inserire la classe RemotingUpload con la stessa signature di quella presente realmente utilizzata (vedremo più avanti la classe reale nel dettaglio):

public class RemotingUpload
{
   public RemotingUpload()
   {}
   bool File(byte[] b,string nomeFile)
   {
      return false;
   }
}

In questo caso non conta il contenuto reale della classe, visto che questa non sarà mai realmente utilizzata in favore di quella che richiameremo con il remoting. Quest'ultima tecnica è la più semplice da implementare anche se comporta la presenza di oggetti zombie nella nostra applicazione (classe che non sarà mai utilizzata se non per la sua signature). Personalmente l'utilizzo dell'interfaccia comune mi è sempre sembrata la migliore per via della chiarezza: per esperienza personale mi sono ritrovato a leggere delle classi da me scritte molti mesi prima e l'identificazione del codice responsabile delle varie chiamate è stato subito rintracciabile grazie alla sua particolarità di gestione di interfacce, mentre con l'uso di coppie di classi (la seconda tecnica esposta) può comportare confusione.

Dopo questa disquisizione prettamente stilistica, ritornando all'esempio, come nel caso del web service avviene la trasformazione del file in un array di byte, quindi nella stringa "location" viene inserito l'IP del computer su cui gira l'applicazione (windows forms, web application o servizio, per il remoting non c'è alcuna differenza), il numero della porta e il nome della funzione che elaborerà il file inviato. Scrivendo "127.0.0.1" abbiamo specificato lo stesso computer su cui gira la web application, impostazione utilizzata per le prove.

L'apertura della comunicazione tra la web application e l'applicazione ricevente viene creata dalla classe "Activator". Questa classe ha una funzione "GetObject" che accetta come parametri il tipo di classe e il percorso dove trovare il servizio remoting attivo. Le operazioni svolte da questa funzione sono innumerevoli e invisibili per lo sviluppatore: innanzitutto viene creata una classe proxy che si prenderà il compito della trasmissione dell'apertura del canale di trasmissione, quindi instanzierà per noi la classe richiamata sul computer remoto, per prendersi cura della serializzazione e deserializzazione dei vari dati inviati e ricevuti. Ovviamente questa è una semplificazione che non tiene conto della vera complessità del funzionamento.

Nell'oggetto "remot" sarà ora presente l'istanza remota della classe e con la funzione "File" lo invieremo finalmente, passando come parametri l'array di byte del file stesso e il suo nome.

Per l'esempio di questo tutorial ho creato una windows forms con un'interfaccia grafica minimale in grado di mostrare i dati ricevuti attraverso remoting:

Immagine

Quello che a noi importa è la funzione di remoting in essa presente. Vediamo dunque il codice:

private void Form1_Load(object sender, System.EventArgs e)
{
   TcpChannel channel = new TcpChannel(1980);
   ChannelServices.RegisterChannel(channel);
   RemotingConfiguration.RegisterWellKnownServiceType(
      typeof(RemotingUpload), "RemotingUpload",
      WellKnownObjectMode.SingleCall);
}

Il remoting, a differenza dei web services, ha la necessità di essere dichiarato esplicitamente. Nel codice qui sopra, infatti, prepariamo la nostra applicazione per la ricezione di chiamate con questa tecnica. Innanzitutto dichiariamo il numero di porta su cui aspetteremo la chiamata. In questo esempio utilizziamo come protocollo di trasmissione il Tcp, più "snello" e veloce del tradizione HTTP. Se nell'esempio qui avessimo voluto utilizzare come protocollo di trasmissione l'HTTP avremmo dovuto usare:

HttpChannel channel = new HttpChannel(80);

Le differenze tra i due tipi di "trasporto" è abissale. Dichiarando come protocollo il Tcp, possiamo trasferire i dati in modo binario, mentre con l'http siamo obbligati - o per meglio dire, sono i proxy creati dal framework, per noi sviluppatori non cambia nulla - alla conversione dei dati nel più comprensibile SOAP. Per esempio, un file di 40KB trasferito con la prima tecnica non subirà trasformazioni durante la trasmissione, mentre nel secondo caso, il file sarà trasformato in SOAP con il conseguente aumento di dimensioni dello stesso di circa il 50% (dato calcolato da prove con il codice qui utilizzato); per lo stesso file i dati che dovranno essere trasferiti saranno circa 60KB. Se mettiamo poi in conto l'operazione non proprio veloce di conversione, vediamo come l'utilizzo del protocollo Tcp e binario sconfigga in prestazioni in maniera netta e inappellabile l'accoppiata SOAP/HTTP...

Tornando al codice, dopo aver dichiarato la porta che utilizzeremo per le chiamate in ingresso, registriamo con la funzione "RegisterWellKnownServiceType" della classe "RemotingConfiguration" il canale utilizzato collegandolo alla classe e al nome che il chiamante dovrà utilizzare per le richieste.

Nelle web application, per mettere a disposizione classi accessibili con il remoting, possiamo eseguire le dichiarazione del codice visto prima direttamente nell'evento "Application_OnStart" nel "gloabl.asax".

Ecco la classe "RemotingUpload" che l'applicazione chiamante utilizzerà per l'invio e la memorizzazione del file:

using System;
using System.IO;

public class RemotingUpload : MarshalByRefObject, IInterfacciaUpload
{
   public bool File(byte[] contenuto,string NomeFile)
   {
      try
      {
         FileStream fs=new  FileStream(
            ConfigurationSettings.AppSettings["percorso"]+NomeFile,
            FileMode.Create,
            FileAccess.Write);
         fs.Write(contenuto,0,contenuto.Length);
         fs.Close();
         return true;
      }
      catch
      {
         return false;
      }
   }
}

Il codice utilizzato per memorizzare il file è identico a quello utilizzato nel caso del web service. Le uniche modifiche sono nella dichiarazione della classe. Si è infatti specificato che deve derivare dalla classe "MarshalByRefObject", dichiarazione obbligatoria per richiamare questa classe in remoting. Inoltre la classe implementa l'interfaccia "IInterfacciaUpload" in modo che il client possa istanziare questa classe anche senza che in essa sia presente la classe "RemotingUpload".

4 pagine in totale: <<Indietro 1 [2] 3 4 Avanti >>

Attenzione: Questo articolo contiene un allegato

Contenuti dell'articolo

Commenti
Dai un voto a questo articolo, ci aiuterà a migliorare il nostro sito (1 è il voto minimo, 5 il massimo).

Per procedere al rating dell'articolo devi essere autenticato.

Aggiungi un nuovo commento »»»
Per inserire un commento, devi registrarti alla nostra community.


TUTORIALS
TOP TEN ARTICOLI
NOTIFICHE

Iscriviti alla nostra newsletter nuoviarticoli per ricevere e-mail le notifiche!

Indirizzo e-mail:
PROVIDER ASP.NET 2.0

Seleziona il database per avere il web.config pronto per Membership, Roles e Profile API.



IN EVIDENZA
MISC