Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

WCF Implementation of the Publisher/Subscriber Model

4.45/5 (19 votes)
9 Jan 2008CPOL5 min read 1   5K  
Implementation of the Publisher and Subscriber model.

pubsubmodel.png

Introduction

The Publisher/Subscriber model is where the Subscriber is the service to which all clients subscribe and the Publisher is the service which sends messages to all clients who have subscribed to the Subscriber service. That is, suppose we have 10 clients and all 10 clients would subscribe to the Subscriber service to receive notifications (client programs are individual programs), and then whenever the required event occurs, the Publisher notifies all those clients registered.

Background

After a thorough reading done here, I understood how the Publisher/Subscriber model is implemented. To know more about this model, have a look here. The reading should let you understand this model.

Then, I went on exploring the Windows Vista SDK, where I found the List Publisher/Subscribe sample. Exploring the same, I was able to understand the logic.

Here is a pictorial representation:

publish-subscriber-logic.png

To explain briefly:

  • We have a WCF Service (the above diagram tells that the WCF Service is hosted in IIS)
  • Design the callback contract between the Service and the Client
  • Setup a Delegate and Event, and the delegate method handler is going to raise that particular event
  • So, when clients subscribe, we increment the event handler which would point to the client’s callback function
  • Now, we build a separate datasource which implements the service callback contract
  • This datasource is responsible to call the Publish function
  • The Publish function is just going to raise the event, and thus every callback in the Event will be called now

Using the code

I have mainly built three components:

  • PubSubService
  • PubSubClient
  • Publisher
PubSubService

This is our main Service which allows the Client to Subscribe, Unsubscribe, and the Publisher to Publish messages to the subscribed clients. Our Service also has a CallBackContract which is going to be our source at the Client for notifications sent out by the Service.

Below is our ServiceContract interface:

C#
[ServiceContract(Namespace = "http://ListPublishSubscribe.Service",
SessionMode = SessionMode.Required, CallbackContract = typeof
(IPubSubContract))]
public interface IPubSubService
{
        [OperationContract(IsOneWay = false, IsInitiating=true)]
        void Subscribe();
        [OperationContract(IsOneWay = false, IsInitiating=true)]
        void Unsubscribe();
        [OperationContract(IsOneWay = false)]
        void PublishNameChange(string Name);
}

It is pretty clear what we have. Our ServiceContract SessionType is set to be SessionMode.Required; so, you have to connect the client, and a session is required and it has three OperationContracts namely:

  • Subscribe
  • UnSubscribe
  • PublishNameChange

The IsOneWay tells that it's not a one way contract, and it's a two way contract meaning that this contract can be called by the Client as well as return some values back to the Client. IsInitiating tells that this contract can initiate a session in the Server/Service.

We have specified the interface IPubSubContract as our CallbackContract. This means that this would be a medium of data exchange between the Service and Client, and using these Callbacks, we can actually make the Service notify the Clients regarding specific events.

Below is our IPubSubContract interface:

C#
public interface IPubSubContract
{
        [OperationContract(IsOneWay = true)]
        void NameChange(string Name);
}

We just have one OperationContract called NameChange. We would be going into this soon.

As now we have our Interfaces defined, it is time to implement our ServiceContract, and below is the class which implements the above IPubSubService interface.

C#
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
 public class PubSubService : IPubSubService
 {
    public delegate void NameChangeEventHandler(object sender, ServiceEventArgs e);
    public static event NameChangeEventHandler NameChangeEvent;

    IPubSubContract ServiceCallback = null;
    NameChangeEventHandler NameHandler = null;

    public void Subscribe()
    {
        ServiceCallback = OperationContext.Current.GetCallbackChannel<IPubSubContract>();
        NameHandler = new NameChangeEventHandler(PublishNameChangeHandler);
        NameChangeEvent += NameHandler;
    }

    public void Unsubscribe()
    {
        NameChangeEvent -= NameHandler;
    }

    public void PublishNameChange(string Name)
    {
        ServiceEventArgs se = new ServiceEventArgs();
        se.Name = Name;
        NameChangeEvent(this, se);
    }

    public void PublishNameChangeHandler(object sender,ServiceEventArgs se)
    {
        ServiceCallback.NameChange(se.Name);

    }
}

We have implemented our already defined three OperationContracts, and also we have defined some delegates and events. What are those?

The logic is simple. Whenever a Client subscribes, we create an event handler and add to our event which is NameChangeEvent. So, what happens here, if “n” number of Clients join, we have “n” number of event handlers referring to those Clients.

How is this accomplished?

Simple. Create a Delegate, associate an event to it, and in the DelegateHandler, we call the ServiceCallback’s NameChange contract when we want to Publish, and since it is a CallbackContract and implemented in the Client, this function would be invoked in the Client, and thus we have published our message to the Client.

So, if you look in the PublishNameChangeHandler, you could see that we invoke the ServiceCallback.NameChange, which makes it clear.

I have hosted the PubSubService in IIS to make things simpler.

Now, let's move on to our PubSubClient.

PubSubClient

Here, we are going to add our WCF Service, implement the IPubSubContract interface to get the Callback from the Service, subscribe to the Service, and be ready to receive messages when our Publisher publishes them.

Add your PubSubService through the Add Service Reference. If you are not familiar, have a look at my post regarding adding a WCF Service to your Application.

Our PubSubClient is a normal Windows Forms Application, having just a Label in the Form, and this Label will be updated when a message is Published by the Publisher.

I have used the PubSubService as the reference for my Service. Once you add the PubSubService, we get our PubSubService.map and PubSubService.cs through which now you can implement the IPubSubContract.

C#
[CallbackBehaviorAttribute(UseSynchronizationContext = false)]
public class ServiceCallback : IPubSubServiceCallback
{
      public void NameChange(string Name)
      {
             Client.MyEventCallbackEvent(Name);
      }
}

Our implementation is straightforward. We implement the NameChange contract here at our Client, and now you should be able to bring out what I meant earlier. This way, when you call from the Service using the Callback, the function in the Client would be called.

What have I done in my NameChange function above?

I have done Marshaling. Marshaling is used when you want to access variables in another environment or thread. And since our Windows Forms is running as a separate thread, to use safe threading, I have used Marshaling here.

Implementing Marshaling is simple. We create a Delegate and associate an Event to it and make the event static. We raise the event from the Service Callback, and update the Label control in our Form.

Below is our client class, and you can see all the Delegates, Events, and also our ServiceCallback implementation done here.

C#
public partial class Client : Form
{
     public delegate void MyEventCallbackHandler(string Name);
     public static event MyEventCallbackHandler MyEventCallbackEvent;

     delegate void SafeThreadCheck(string Name);

     [CallbackBehaviorAttribute(UseSynchronizationContext = false)]
     public class ServiceCallback : IPubSubServiceCallback
     {
         public void NameChange(string Name)
         {
             Client.MyEventCallbackEvent(Name);
         }
     }

     public Client()
     {
          InitializeComponent();            

          InstanceContext context = new InstanceContext(new ServiceCallback());
          PubSubServiceClient client = new PubSubServiceClient(context);

          MyEventCallbackHandler callbackHandler = new MyEventCallbackHandler(UpdateForm);
          MyEventCallbackEvent += callbackHandler;

          client.Subscribe();
     }

     public void UpdateForm(string Name)
     {
          if (lblDisplay.InvokeRequired)
          {
              SafeThreadCheck sc = new SafeThreadCheck(UpdateForm);
              this.BeginInvoke(sc, new object[] { Name });
          }
          else
          {
              lblDisplay.Text += Name;
          }
     }

 }

The only thing to keep in mind is the Marshaling. Here, I use the BeginInvoke method so that it doesn't wait for that delegate handler to complete, and the UI thread continues to do its work. If you use the Invoke method, the UI thread waits till its operation is completed. It actually depends on whether to use BeginInvoke or Invoke. You can also use Invoke here in the place of BeginInvoke.

Publisher

Publisher is the most simplest of all. We add our PubSubService, create the Service object, and just invoke the PublishNameChange contract, and thus that would invoke the ServiceCallback’s NameChange contract to the subscribed Clients, and thus exchanging the data with the Clients.

Below is the Publisher code:

C#
public partial class Publisher : Form
{
     InstanceContext context = null;
     PubSubServiceClient client = null;

     public class ServiceCallback : IPubSubServiceCallback
     {
         public void NameChange(string Name)
         {
              MessageBox.Show(Name);
         }
     }

     public Publisher()
     {
         InitializeComponent();
     }

     private void btnPublish_Click(object sender, EventArgs e)
     {
         context = new InstanceContext(new ServiceCallback());
         client = new PubSubServiceClient(context);
         client.PublishNameChange(txtMessage.Text);
         client.Close();
     }
}

Now, we are ready to subscribe and publish ;)

Hope you had a good time reading my article on how to implement Publisher/Subscriber using WCF. If you have any queries, please feel free to drop me an email or start a discussion below.

History

  • Jan 10,2008 - Added the article.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)