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

Robust Interapplication Communications using Double-Simplex WCF

4.96/5 (14 votes)
9 Mar 2008CPOL4 min read 1   647  
An unbreakable method for two applications on the same desktop to exchange data
Pollux

Introduction

I needed to find a way for two applications running on the same desktop to communicate with each other. There are a number of ways to do this, but since I had not used WCF (Windows Communication Foundation) before, I thought it might be fun to try it.

Background

Under WCF, one application can run a WCF Host and the other a WCF Client. The Client connects to the Host, and can then send data to the Host and request data from the Host. If a callback is used, then a Host-side event can also send data back to the Client, without the Client having requested it.

Problem

WCF seemed ideal, but I quickly found a snag.

Since both of my applications were ordinary desktop applications that could be started and stopped by the user, it was not predictable if both applications would be running at the same time. This was expected, and the desired behaviour was for the application sending the data to fail gracefully if the other application was not running.

From the Client side, there was no problem. The Client would simply connect to the Host (if not already connected) and send the data. If the Host was not available, the Client would fail gracefully.

From the Host side, there was a problem. If there was no existing connection (for instance if the Host had been stopped and started, breaking the connection), then it would not be possible for an event on the Host to send data to the Client. The Client would first have to initiate the connection so that the Host could talk to it.

Solutions

Two solutions came to mind: Have the Client poll the Host periodically using a timing loop to see if it was running, and establish communications; or have the Host tell the Client to connect by sending a message via a file which the Client was monitoring. Both were horrible hacks and quickly discounted.

What I decided to do was run two separate WCF connections (double simplex). Each application would run a WCF Host for incoming messages and each application would run a WCF Client for outgoing messages. This is a pretty robust solution and will not be broken by stopping and starting the applications. The WCF Client simply re-establishes the connection if needed.

The Downloads

I have provided two downloadable projects, so you can run each of them in a separate instance of Visual Studio. Just run and go. It should all work "out of the box".

You may like this format, or you may not. I suppose I could have put both in the same solution, but I hate it when a CodeProject article has a single solution with two projects that need to run at the same time. Invariably, I end up running one of them as an EXE from Windows Explorer and the other in Visual Studio, and can't debug both at the same time.

Note that both projects are absolutely identical, apart from the fact that they have different names and the names of the pipes are reversed, so that one talks on the pipe which the other uses for listening and vice-versa.

Note also that one project does not reference the other. We rely on having identical copies of Gemini.cs in each. Again you may or may not like this, but you can easily do it the other way if you want to.

Using the Code

I have encapsulated the working code in the file Gemini.cs and both projects have an identical copy. It should be possible to use this unaltered, simply by dropping it into your own projects and calling it as I have.

I'm not going to get deeply into how WCF works. This is intended as a practical working code clip you can use, not a tutorial. WCF is documented very thoroughly elsewhere, for instance here.

This is the calling code in the sample form, showing how to use Gemini.cs.

C#
using Gemini;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace Castor
{
  public partial class Form1 : Form
  {
    private Gemini.Gemini gemini;

    public Form1()
    {
      InitializeComponent();
      gemini = new Gemini.Gemini("Castor", "Pollux", 
            WindowsFormsSynchronizationContext.Current);
      gemini.OnReceiveMessage += 
            new Gemini.Gemini.ReceiveMessageEventHandler(gemini_OnPassMessage);
    }

    private void button1_Click(object sender, EventArgs e)
    {
      if (gemini.SendMessage(this.textBox1.Text))
      {
        display(" [SENT] " + this.textBox1.Text);
      }
      else
      {
        display(" [FAIL] " + this.textBox1.Text);
      }
    }

    private void gemini_OnPassMessage(object sender, MessageEventArgs e)
    {
      display(" [RECV] " + e.Message);
    }

    private void display(string text)
    {
      if (this.listBox1.Items.Count > 14)
      {
        this.listBox1.Items.RemoveAt(0);
      }
      this.listBox1.Items.Add(DateTime.Now.ToLocalTime() + text);
    }
  }
}

Bonus

If you include the third parameter, the Synchronization Context, the event for an incoming message will come back on that thread. If you created the Gemini instance from the main UI thread (as will probably be the case), this avoids any cross-threading problems when updating Windows Controls. No need for InvokeRequired.

Caveat

I'm no expert on WCF, in fact this is my first try. The code does not appear to have any issues. It does not seem to chew memory or generate infinite threads, but let me know if you have any comments. I'll update if and when required.

License

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