Click here to Skip to main content
Click here to Skip to main content

Robust Interapplication Communications using Double-Simplex WCF

By , 9 Mar 2008
 
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.

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)

About the Author

joomlathug
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionGreat article PinmemberStavrosLag30 Aug '12 - 4:33 
GeneralMy vote of 5 Pinmemberhosfelds24 Aug '12 - 9:12 
QuestionHow can you convert, but using NetTCPBindings? Pinmemberbrcordova28 Feb '11 - 12:37 
GeneralMy vote of 5 PinmemberMember 81270022 Sep '10 - 13:37 
QuestionCallbacks? PinmemberTomMam19 Feb '10 - 5:22 
GeneralMy vote of 1 Pinmemberklorofill12 Oct '09 - 6:27 
GeneralAwesome! + VB.NET version Pinmemberabakshi17 Jul '09 - 22:13 
GeneralRun 2 EXE from the Same IDE PinmemberAzlan David8 Apr '08 - 7:14 
GeneralError Message Pinmembersam.hill7 Mar '08 - 9:00 
GeneralClever avoidance of thread issues Pinmemberbrian.hawley7 Mar '08 - 1:42 
GeneralGreat article PinmemberBat Gurl7 Mar '08 - 1:13 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 9 Mar 2008
Article Copyright 2008 by joomlathug
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid