2

I have one WCF service that exposes two operations - IncrementList() and GetList(). Client B connects to the service, calls GetList() and displays to the user. Client A has the ability to update this list by calling IncrementList().
I want Client B to get notified when IncrementList() is called so it can call GetList() again to display the updated data.

Could you please outline how you'd implement this? CallBacks? Duplex? Publisher/Subscriber?
Anything new in WCF 4.0 that aids in this scenario?

Service diagram

Thanks!

Gus Cavalcanti
  • 10,527
  • 23
  • 71
  • 104
  • 1
    what is the load you expect ? are there any proxies/firewalls etc. ? how fast does the notification need to be ? – Yahia Nov 03 '11 at 08:44
  • What is the question? The answer to your current question is simply **yes** because notifications can be achieved only by duplex binding which uses callbacks and duplex binding is core of publish/subscribe message exchange pattern. There is nothing more in WCF 4 to support this. – Ladislav Mrnka Nov 03 '11 at 09:34
  • Yahia, no proxies or firewalls and the notification does not need to be real time. – Gus Cavalcanti Nov 03 '11 at 15:20
  • Ladislav Mrnka, sorry - I realize my question is quite vague and it is clear that I am very green with WCF... My question is really "how would you implement this?" – Gus Cavalcanti Nov 03 '11 at 15:22

1 Answers1

5

Something you should decide up front is if you want to push the whole list when its incremented (heavy) or just the updated item to each client. The code below is for push whole list but easy to modify this just to push the updated object (recomended).
At app start Client B should call Register_client and then GetList. Subsequently it will be notified via call back when list is incremented (the client needs to implient this interface)
The call GetList requires a duplex channel and SessionMode.Required.

Your server should impliment:

[ServiceContract(SessionMode = SessionMode.Required
                 CallbackContract = typeof(IMyCallback))]
    public interface IMyServer {

    [OperationContract]
    void Register_client();

    [OperationContract(IsOneWay = true)]
    void IncrementList();

    [OperationContract]
    ListObject[] GetList();
}  

[DataContract]
public class ListObject {
    [DataMember]...
}

Your client should impliment:

public interface IMyCallback {
    [OperationContract(IsOneWay = true)]
    void PushList(ListObject[] list);
}

Register client just needs store client callback interface for use when list is incremented something like:

public override void Register_client() {
    // Store callback interfaces for all connected clients:
    IMyCallback callback = OperationContext.Current.GetCallbackChannel<IGatewayServerCallback>();
    if (clients.Contains(callback) == false)
    clients.Add(callback);
    Trace.WriteLine(string.Format("Client connection established ({0})", clients.Count));
}

Where:

private List<IMyCallback> clients = new List<IMyCallback>();

The impliementation of IncrementList should do a callback to push new list (or better just the new object that was added to list) to client - something like:

for (int i = 0; i < clients.Count; i++) {
    if (((ICommunicationObject)clients[i]).State == CommunicationState.Opened) {
    try {
        clients[i].PushList(list);
    }
    catch (Exception e) {
        clients.RemoveAt(i--);
        Trace.WriteLine(e);
        Trace.WriteLine(string.Format("Removing client {0} (exception).", i + 1));
    }
}

The callback implimentation (client side) looks something like:

public class MyCallback : IMyCallback {
public void PushList(ListObject[] list) {
    // Were client side - update list code here...
}

Probably this callback implimentation needs a reference to some object that holds the list data - probably this is passed in to contructor (not shown).

When you instantiate your proxy object you will need to pass an instance of callback to the proxy constructor - something like:

MyServerClient client_proxy = new MyServerClient(new InstanceContext(my_callback, binding_str)
Ricibob
  • 7,505
  • 5
  • 46
  • 65
  • Ricibob, thank you so much for such a complete answer! I am obviously green in WCF and have a question: I was thinking that I could simple expose an event from the service and the client would subscribe to it. The handler of the event would then call GetList(). Is this possible? I am not asking to write the code for me, but could you please outline the steps? :) thank you!!! – Gus Cavalcanti Nov 03 '11 at 15:24
  • @GustavoCavalcanti Im fairly green myself with WCF but have an application based more or less on the above working well. It is my understanding that you can't expose an event directly on a server interface. Instead what I do here is expose a method on the callback interface with a similar signature to the event and then client side the implimentation of that method fires the event - just passing on the args. Our UI app works with events on an interface - but we can plug in a local implimentation of interface (normal events) or a remote wcf proxy implimentation that works with method->event – Ricibob Nov 03 '11 at 17:30
  • Ricibob, could you please show the code for PushList? Thanks! – Gus Cavalcanti Nov 04 '11 at 17:23