Wednesday, April 18, 2012

WCF Call Back

Client subscribes to service and service calls clients back and that is what this is about.

1) A normal WCF contract for server(impementation) and client(for proxy)
[ServiceContract]
interface IMessage    
{
        [OperationContract]
        void AddMessage(string message);
 }
2) A special interface(not a contract) for server(proxy) and client(implementation)
 interface IMessageCallback    
{
        [OperationContract(IsOneWay = true)]
        void OnMessageAdded(string message, DateTime timestamp);
 }
3) Add subscribe mechanism to normal WCF contract (given in step 1)
   [ServiceContract(CallbackContract = typeof(IMessageCallback))]
    public interface IMessage {
        [OperationContract]
        void AddMessage(string message);

        [OperationContract]
        bool Subscribe();

        [OperationContract]
        bool Unsubscribe();
    }

4) Implentation of normal contract given in step 3
a) a list to store subscribers
private static readonly List<IMessageCallback> subscribers = new List<IMessageCallback>();
b) get subscriber(callback channel to client)
IMessageCallback callback = OperationContext.Current.GetCallbackChannel<IMessageCallback>();
c) add subscriber to list
subscribers.Add(callback);
complete code:

public bool Subscribe()
{
    try {
        IMessageCallback callback = OperationContext.Current.GetCallbackChannel<IMessageCallback>();
        if (!subscribers.Contains(callback))
            subscribers.Add(callback);
        return true;
    }
    catch {
        return false;
    }
}

public bool Unsubscribe()
{
    try {
        IMessageCallback callback = OperationContext.Current.GetCallbackChannel<IMessageCallback>();
        if (subscribers.Contains(callback))
            subscribers.Remove(callback);
        return true;
    }
    catch {
        return false;
    }
}
public void AddMessage(string message)
{
    subscribers.ForEach(delegate(IMessageCallback callback)
    {
        if (((ICommunicationObject)callback).State == CommunicationState.Opened)
        {
            callback.OnMessageAdded(message, DateTime.Now);        }
        else {
            subscribers.Remove(callback);
        }
    });
}
5) add a suitable binding in config
<endpoint address ="" binding="wsDualHttpBinding" contract="WCFCallbacks.IMessage">

6) Client implementation
a) implement call back contract(given in step 2)
b) dispose mechanism needed
c) a context is required
 [CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
class Sender : IMessageCallback, IDisposable
{
    private MessageClient messageClient; public void Go()
    {
        InstanceContext context = new InstanceContext(this);
        messageClient = new MessageClient(context, "WSDualHttpBinding_IMessage");

        for (int i = 0; i < 5; i++)
        {
            string message = string.Format("message #{0}", i);
            Console.WriteLine(">>> Sending "+message);
            messageClient.AddMessage(message);
        }

    }
public void OnMessageAdded(string message, DateTime timestamp)
    {
        Console.WriteLine("<<< Recieved {0} with a timestamp of {1}", message, timestamp);
    }

    public void Dispose()
    {
        messageClient.Unsubscribe();
        messageClient.Close();
    }
}

Courtesy

No comments:

Post a Comment