Duplex calls in indigo beta 1

There are two things you need to remember when making a duplex contract under indigo beta 1, the first is that you can only use one way calls on the contract and you also need to specify the callback contract in the main contract.

On the client side to open a call to a duplex contract you need to use the CreateDuplexChannel call on the ChannelFactory which specifies a service to callback on and to get the channel to talk back on on the service side you use the OperationContext.Current.GetCallbackChannel<CallbackContract> call.

Here is the contract to be used:

interface IPong
{
    [OperationContract(IsOneWay=true)]
    void Pong(int n);
}

[ServiceContract(CallbackContract=typeof(IPong))]
interface IPing
{
    [OperationContract(IsOneWay=true)]
    void Ping(int n);
}

The [ServiceContract] attribute has the CallbackContract attrbribute associated with it and this lets you specify the callback contract to use to talk back to the client.  If this is specified on a contract then you must use CreateDuplexChannel to open a connection to the channel, using CreateChannel will throw an exception saying that you need to use a duplex contract.

The service will look like this:

[ServiceBehavior]
class PingService : IPing
{
    public void Ping(int n)
    {
        Console.WriteLine("Ping {0}", n);

        if (n < 0)
        {
            OperationContext.Current.GetCallbackChannel<IPong>().Pong(n+1);
        }
        else if (n > 0)
        {
            OperationContext.Current.GetCallbackChannel<IPong>().Pong(n-1);
        }
    }
}

This uses the callback channel to call back onto the client.  When the client opens up a channel on the client side it needs to specify an instance of the IPong interface to talk back to.  This is the code that will be called and used the the duplex channel request comes in from the service.

class App
{
public void MakeChannel()
{
     PongCallback pong = new PongCallback();
     IPingChannel ping = ChannelFactory.CreateDuplexChannel<IPingChannel>(pong, TcpAddress, TcpBinding);
     using (ping)
     {
         ping.Ping(5);
         Console.WriteLine("Press a key to exit");
         Console.ReadKey();
         ping.Close();
     }
}
}

class PongCallback : IPong
{
    public void Pong(int n)
    {
        Console.WriteLine("Pong {0}", n);

        if (n < 0)
        {
            OperationContext.Current.GetCallbackChannel<IPingChannel>().Ping(n+1);
        }
        else if (n > 0)
        {
            OperationContext.Current.GetCallbackChannel<IPingChannel>().Ping(n-1);
        }
    }
}