PollingDuplexBinding Sample Implementation Part 2

Last time I provided a sample implementation of a PollingDuplexBinding service that could publish messages. Note that as with the server side, a reference must be added to System.ServiceModel.PollingDuplex assembly. I’m now going to give the client side implementation to show how to consume the service. In the previous post I showed the callback interface. Show below as ILogServiceCallback.

/// <summary>
/// Callback for duplex service to push log messages to client.
/// </summary>
public interface ILogServiceCallback
{
    /// <summary>
    /// Pushes the message to the client via the duplex service.
    /// </summary>
    /// <param name="message">The message.</param>
    [OperationContract(IsOneWay=true)] 
    void PushMessage(LogMessage message);
}

And the implementation of the ILogServiceCallback interface.

public class LogCallback : ILogServiceCallback
{
    public event EventHandler<MessageReceivedEventArgs> MessageReceived;
 
    public void PushMessage(LogMessage message)
    {
        if (MessageReceived != null)
        {
            MessageReceived(this, new MessageReceivedEventArgs(message));
        }
    }
}

The event handler should probably be included on the interface and would be a good refactoring move however since I’m ‘newing’ up this object I’m just taking the shortcut and going directly against the class, especially since there isn’t a lot going on in it. Creating a service proxy to listen for messages pushed from the PollingDuplexService is a bit different than creating a standard service proxy.

public class LogSubscriber : ILogSubscriber
{
    private readonly ILogger logger;
    private DuplexChannelFactory<ILogService> channelFactory;
    private LogCallback callbackInstance;
    private ILogService proxy;
    private DispatcherTimer timer;

    public event EventHandler<MessageReceivedEventArgs> MessageReceived;
 
    public LogSubscriber(ILogger logger)
    {
        this.logger = logger;
           
        Initialize();
    }

    public void Start()
    {
        logger.Log("Opening channel factory and creating service proxy for duplex binding.");

        channelFactory.Open();
        proxy = channelFactory.CreateChannel();
        proxy.BeginSubscribe(proxy.EndSubscribe, null);

        timer.Start();
    }

    public void Stop()
    {
        logger.Log("Stoping duplex binding service.");

        callbackInstance.MessageReceived -= callbackInstance_MessageReceived;

        timer.Stop();
        channelFactory.Close();
    }

    private void Initialize()
    {
        callbackInstance = new LogCallback();
        callbackInstance.MessageReceived += callbackInstance_MessageReceived;

        channelFactory = new DuplexChannelFactory<ILogService>(new InstanceContext(callbackInstance), new PollingDuplexHttpBinding(),
            new EndpointAddress("http://localhost/DuplexServices/LogDuplexService"));

        timer = new DispatcherTimer {Interval = new TimeSpan(0, 8, 0)};
        timer.Tick += (o, e) => proxy.BeginKeepAlive(KeepAliveCallback, null);
    }

    private void callbackInstance_MessageReceived(object sender, MessageReceivedEventArgs e)
    {
        if (MessageReceived != null)
        {
            MessageReceived(this, e);   
        }
    }

    private void KeepAliveCallback(IAsyncResult result)
    {
        proxy.EndKeepAlive(result);
    }
}

In the above implementation there are a few things to note. First in the Initialize method an instance of the callback object is created and the MessageReceived event handler is subscribed to. This is the method that will be called when a message is pushed from the server to the client. Next, a DuplexChannelFactory is created. This is different than the standard ChannelFactory specific for the DuplexBindingService with the callback instance passed in as part of the constructor. Finally, notice the timer firing every 8 minutes. This calls the KeepAlive operation in order to maintain the connection which expires every 10 minutes unless a service call is made.

Whoever subscribes to the MessageReceived event of the LogSubscriber class can do what they want with the LogMessages. In my client, I add the log message to an ObservableCollection that is bound to a list box in which to display the log messages. The results in a “console” like appearance for log messages that are displayed in real time.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s