9

Sep

WCF 4.5 WebSocket per Metro app e non

Ciao a tutti

 

ecco un semplice esempio d’uso del nuovo netHttpBinding per WCF, elemento principale della nuova tecnologia WebSocket

 

Già da tempo WCF è in grado di usare un canale bidirezionale per comunicare in modo attivo con il client, in pratica evitando di dover avere dei timer sul client per chiamare il server in modo ciclico per ricevere eventuali aggiornamenti.

Noto da sempre come paradigma di comunicazione Duplex (al posto del normale request-response anche detto Simplex), WCF supporta la programmazione di servizi su questo paradigma con l’ormai legacy wsDualHttpBinding, che però costringeva il client ed il server ad avere una comunicazione diretta tra i due (con eventuale dns o IP pubblico finanche per il client).

La novità del WebSocket quindi è proprio l’abbandono di questi requisiti con un canale più potente di comunicazione, che però ha come requisito l’uso di Windows 8

 

DEMO:

 

Creiamo così un semplice servizio bidirezionale:

[ServiceContract(CallbackContract = typeof(IPokeServiceCallback))]
public class PokeService
{
    [OperationContract(IsOneWay = true)]
    public async Task StartGetTime()
    {
        var callback = OperationContext.Current.GetCallbackChannel();

        await Task.Delay(2000);

        while ((callback as IChannel).State == CommunicationState.Opened)
        {
            await callback.GetUpdatedTime(string.Format("{0}", DateTimeOffset.Now));
            await Task.Delay(1000);
        }
    }
}

[ServiceContract()]
public interface IPokeServiceCallback
{
    [OperationContract(IsOneWay = true)]
    Task GetUpdatedTime(string time);
}

 

questo servizio è composto da un servizio con contratto integrato (che sostituisce la più comune interfaccia), e da un’interfaccia per definire il canale inverso, quello che costituisce le chiamate dal server al client

 

la configurazione del servizio è abbastanza normale, tranne per il nuovo binding:


              binding="netHttpBinding" contract="MyService.PokeService" />

              binding="mexHttpBinding" contract="IMetadataExchange" />

 

il client invece per le applicazioni metro (win8) contiene una semplice TextBlock per visualizzare l’ora:


   
       
   

e questo è il codice in ottica MVVM

public sealed partial class MainPage : Page, INotifyPropertyChanged
{
    public MainPage()
    {
        this.InitializeComponent();

        var c = new Poke.PokeServiceClient();

        c.GetUpdatedTimeReceived += c_GetUpdatedTimeReceived;
        c.StartGetTimeAsync().ContinueWith(t =>
            {
                CurrentTime = "wait...";
                Notify("CurrentTime");
            });
    }

    void c_GetUpdatedTimeReceived(object sender, Poke.GetUpdatedTimeReceivedEventArgs e)
    {
        CurrentTime = e.time;
        Notify("CurrentTime");
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private async void Notify(string name)
    {
        await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
            () =>
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(name));
            });
    }

    public string CurrentTime { get; set; }
}

come si nota, l’uso del pattern await-async è d’obbligo, ma anche semplice. in pratica si dichiara un metodo asincrono con l’async, e si richiede l’attesa dell’esecuzione in maniera nuovamente sincrona quando necessario con l’await

 

un evento poi riceverà le chiamate che il server farà in automatico al client in modo ciclico (in questo esempio il server manda una chiamata al client ogni secondo)

 

 

un client invece non Metro, sarà simile a questo:

class Program
{
    static void Main(string[] args)
    {
        var c = new Poke.PokeServiceClient(new InstanceContext(new PokeServiceCallbackClient()));
        c.StartGetTimeAsync().ContinueWith(t =>
            {
                Console.WriteLine("wait...");
            });

        Console.ReadLine();
    }

    public class PokeServiceCallbackClient : Poke.PokeServiceCallback
    {
        public void GetUpdatedTime(string time)
        {
            Console.WriteLine(time);
        }
    }
}

 

l’unica differenza è che nel caso di applicazioni non metro dobbiamo implementare noi il client inverso che risponde alle chiamate del server implementando il metodo (che in metro è l’evento) tramite l’interfaccia del callback (appunto la chiamata inversa)

 

spero di essere stato almeno comprensibile se non del tutto chiaro Sorriso

comunque, l’esempio completo è QUI (ovviamente per VS2012)

 

a presto

by Antonio Esposito on 9/9/2012