Confessions of a Dangerous Mind

Brain.FlushBuffer()
posts - 176, comments - 234, trackbacks - 93

Silverlight Beta2: Going Full-Duplex!

Con l'arrivo della Beta2 di Silverlight è compresa una delle features da me più attese: la comunicazione full duplex. Una piccola premessa è d'obbligo, anche perchè non tutti possono conoscere le problematiche di una comunicazione full duplex ed è forse anche proficuo fare un confronto con la comunicazione half duplex.

Il paradigma Request/Response, cui tutti siamo abituati, può essere considerato a tutti gli effetti una comunicazione half duplex; essa cioè avviene in un solo senso, dal client al server. Le pagine ASP, i web services, sono tutti esempi di comunicazione half duplex, dove il client effettua una richiesta al server e quest'ultimo fornisce (a volte) una risposta.

Nella maggior parte dei casi, per applicazioni three-tier basate su Web Services, questo approccio è ottimale: l'applicazione server è scalabile, nel senso che una volta fornita la risposta le risorse impiegate per fornirla vengono rilasciate, ed il client è molto semplice; la comunicazione avviene attraverso una serie di metodi il più delle volte incorporati in una classe proxy autogenerata.

Ci sono dei casi, però, in cui questo tipo di comunicazione non è nè consigliabile, nè alle volte fattibile. Si tratta dei casi in cui si desidera che sia il server a comunicare con il client, e non viceversa. Si parla in questo caso anche di Server Push. Le applicazioni che possono avvalersi di una tale tecnologia sono innumerevoli, e vanno dalla semplice chat, all'applicazione che fornisce in tempo reale i dati di una partita di _______ (scegliete voi lo sport!), al gioco multiplayer, a semplici programmi di alerting, a complesse applicazioni di monitoraggio di impianti.

Questa funzionalità di comunicazione, peraltro già presente in prodotti come Flash, è ora incorporata in Silverlight, e basa il suo fondamento sulle solide basi di Windows Communication Foundation. La descrizione di come debba essere implementata una comunicazione full duplex, in cui i dati vengano inviati dal server al client, la potete trovare nella documentazione ufficiale di Silverlight, qui e qui.

Non voglio riportare inutilmente il codice, che potete trovare nell'esempio fornito dalla documentazione, perfettamente funzionante; bensì ho creato una piccola classe Duplex Helper, che agevola la parte più "fastidiosa" della comunicazione duplex di Silverlight, ovvero la gestione degli eventi sul client.

La classe in oggetto espone tre metodi e due eventi:

  • OpenChannel(string URL): apre il canale all'URL specificato.
  • CloseChannel(): chiude il canale.
  • SendMessage(string messageId, string messageBody): invia il messaggio di tipo messageId con messageBody sul canale che deve essere stato aperto in precedenza. La stringa MessageId deve essere fomattata con il namespace del servizio, l'interfaccia che forma il contratto e il metodo che si vuole invocare, mentre non c'è nessuna limitazione per il messageBody.

Gli eventi sono:

  • OnOpenChannelCompleted(): sollevato al completamento dell'apertura del canale. Utile per notificarlo all'utente.
  • OnOpenChannelError(): sollevato se si verifica un errore durante l'apertura del canale.
  • OnSendMessageCompleted(): sollevato al termine dell'invio di un messaggio.
  • OnSendMessageError(): sollevato al verificarsi di un errore durante l'invio di un messaggio.
  • OnMessageCallBackReceived(): sollevato all'arrivo di un messaggio dal server (server push). Può essere utilizzato per fare parse del messaggio.

Il codice per utilizzare questa classe è il seguente, da collocare in una pagina di un progetto Silverlight:

   1: public DuplexClient()
   2:         {
   3:             InitializeComponent();
   4:             // Grab a reference to the UI thread. (Diagnostic purpose)
   5:             uiThread = SynchronizationContext.Current;
   6:  
   7:             _duplexHelper = new DuplexHelper();
   8:  
   9:             _duplexHelper.OnMessageCallBackReceived+=new DuplexHelper.MessageCallBackReceivedHandler(_duplexHelper_OnMessageCallBackReceived);
  10:             _duplexHelper.OnOpenChannelCompleted += new EventHandler(_duplexHelper_OnOpenChannelCompleted);
  11:             _duplexHelper.OnOpenChannelError += new DuplexHelper.OpenChannelErrorHandler(_duplexHelper_OnOpenChannelError);
  12:             _duplexHelper.OnSendMessageError += new DuplexHelper.SendMessageErrorHandler(_duplexHelper_OnSendMessageError);
  13:             //Apro il canale per la comunicazione
  14:             _duplexHelper.OpenChannel("http://localhost:9000/NorthwindService/Service.svc");                                  
  15:         }
  16:  
  17:         void _duplexHelper_OnSendMessageError(object sender, DuplexCommunicationErrorEventArgs e)
  18:         {
  19:             uiThread.Post(WriteText, e.InnerException.Message + Environment.NewLine);
  20:         }
  21:  
  22:         void _duplexHelper_OnOpenChannelError(object sender, DuplexCommunicationErrorEventArgs e)
  23:         {
  24:             uiThread.Post(WriteText, e.InnerException.Message + Environment.NewLine);
  25:         }
  26:  
  27:         void _duplexHelper_OnOpenChannelCompleted(object sender, EventArgs e)
  28:         {
  29:             uiThread.Post(WriteText, "Channel opened and ready!" + Environment.NewLine);
  30:         }
  31:  
  32:         void _duplexHelper_OnMessageCallBackReceived(object sender, MessageCallBackReceivedEventArgs e)
  33:         {
  34:             //qui si può effettuare il parsing del messaggio
  35:             string text = e.ReceivedMessage.GetBody<string>();
  36:             uiThread.Post(WriteText, "Message from server: " + text + Environment.NewLine);
  37:         }
  38:  
  39:         private void Button_Click(object sender, RoutedEventArgs e)
  40:         {
  41:             //Questo è un esempio di chiamata. Ovviamente l'invio di un messaggio non ha valori di ritorno.
  42:             string _message = "My Goods";
  43:             _duplexHelper.SendMessage("Silverlight/IDuplexService/Order",_message);
  44:             uiThread.Post(WriteText, "Client says: Sent order of " + _message + Environment.NewLine);
  45:             uiThread.Post(WriteText, "Service will call back with updates" + Environment.NewLine);
  46:         }
  47:  
  48:         void WriteText(object text)
  49:         {
  50:             reply.Text += (string)text;
  51:         }

L'esempio riportato funziona con l'esempio di service presente nella documentazione ufficiale, che vi invito a consultare (MSDN docet!). La classe è "in via di realizzazione", per cui c'è sicuramente spazio per ottimizzazioni e/o aggiunte.

L'utilizzo della comunicazione FullDuplex è comunque da approfondire in termini di scalabilità. Potete trovare un articolo di Dan Wahlin che parla della parte "service" a questo indirizzo. Bisogna infatti capire quante e quali risorse vengano impiegate, soprattutto dal server, per mantenere attiva una simile infrastruttura. Spero di avere l'occasione di sondare in futuro, magari con la versione RTM, l'effettivo impiego di risorse e l'applicabilità di un'architettura così affascinante ed utile.

Print | posted on mercoledì 18 giugno 2008 19:34 |

Feedback

Gravatar

# re: Silverlight Beta2: Going Full-Duplex!

Ottimo post! Penso tu sia il primo a parlare di questa nuova feature :-)
19/06/2008 05:48 | Giorgio
Gravatar

# re: Silverlight Beta2: Going Full-Duplex!

Veramente interessante.
19/06/2008 12:01 | anonimo
Gravatar

# re: Silverlight Beta2: Going Full-Duplex!

Condivido le opinioni positive fin'ora espresse.
Ottima segnalazione davvero, penso sia una delle features più interessati della Beta 2; non ho ancora avuto modo di testarlo di persona, soprattutto per quel che riguarda il peso lato server di tale infrastruttura.
19/06/2008 19:36 | MarcoG
Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET