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

Independent Startup Order of Communicating Applications

0.00/5 (No votes)
22 May 2011CPOL2 min read 7.4K   47  
A simple example showing how to implement the communication where the client application can start to communicate before the service application is running.

Summary: A simple example showing how to implement the communication where the client application can start to communicate before the service application is running.

Introduction

Typically, the startup order matters in the interprocess communication. It means, the client application assumes that the service application is running and is ready to communicate. This behavior does not have to be a problem for systems, where the service is running most of the time and clients start and stop regularly.
But for systems consisting of more applications running on separate machines and starting approximately at the same time, this behavior causes that somebody (or something) must start the system in a defined order, what complicates life and makes the startup error prone.

The example below implements a simple client-service communication where communicating applications can start independently from each other and the client can start to communicate even before the service is able to receive messages.

The example is based on the Eneter Messaging Framework that provides components for various communication scenarios.
(The framework is free and can be downloaded from http://www.eneter.net. The online help for developers can be found at http://www.eneter.net/OnlineHelp/EneterMessagingFramework/Index.html.)

Buffered Messaging

To implement the independent startup order behavior, we will use Buffered Messaging from the Eneter Messaging Framework.
In case the receiving application is not connected, the Buffered Messaging automatically tries to open the connection and meanwhile stores sent messages into the buffer. Then, when the connection is open, it sends the stored messages to the receiver.

In our independent startup order scenario, if the client starts before the service and sends some message, the message is stored in the buffer. Then, when the service is started and the connection is open, the message from the buffer is sent to the service.

Image 1

Service Application

The service application is a simple console application communicating via TCP and returning the time. The whole implementation is very simple.

C#
using System;
using Eneter.Messaging.EndPoints.TypedMessages;
using Eneter.Messaging.MessagingSystems.MessagingSystemBase;
using Eneter.Messaging.MessagingSystems.TcpMessagingSystem;

namespace TimeService
{
    class Program
    {
        // The message receiver.
        // It receives 'string' and responses 'DateTime'.
        // Note: the 'string' is not used in this example.
        static IDuplexTypedMessageReceiver<DateTime, string> myReceiver;

        static void Main(string[] args)
        {
            // Create TCP based messaging.
            IMessagingSystemFactory aTcpMessaging = new TcpMessagingSystemFactory();
            IDuplexInputChannel anInputChannel = 
                aTcpMessaging.CreateDuplexInputChannel("tcp://127.0.0.1:7083/");

            // Create typed message receiver.
            IDuplexTypedMessagesFactory aTypedMessagesFactory = 
                new DuplexTypedMessagesFactory();
            myReceiver = aTypedMessagesFactory.CreateDuplexTypedMessageReceiver
            <DateTime, string>();
            myReceiver.MessageReceived += OnMessageReceived;

            // Attach the receiver to the channel and start listening.
            myReceiver.AttachDuplexInputChannel(anInputChannel);

            Console.WriteLine("The service is listening.");
            Console.WriteLine("Press Enter to stop.");
            Console.ReadLine();

            myReceiver.DetachDuplexInputChannel();
        }

        static void OnMessageReceived(object sender, 
        TypedRequestReceivedEventArgs<string> e)
        {
            // Process the incoming request:
            // Just return the current time.
            myReceiver.SendResponseMessage(e.ResponseReceiverId, DateTime.Now);
        }
    }
}

Client Application

The client application is a simple application using the service to retrieve the exact time.
The client application can start and can request the time before the service application is running.
In such a case, the request is stored in the buffer. Then, when the service is ready, the request is delivered and the service responses the time.

Try the following scenario:

  1. Start the client application.
  2. Invoke the request to get the exact time.
  3. Wait few seconds and start the service application.
  4. The client displays the time from the service.

The implementation is very simple.

C#
using System;
using System.Windows.Forms;
using Eneter.Messaging.EndPoints.TypedMessages;
using Eneter.Messaging.MessagingSystems.Composites.BufferedMessagingComposit;
using Eneter.Messaging.MessagingSystems.MessagingSystemBase;
using Eneter.Messaging.MessagingSystems.TcpMessagingSystem;

namespace TimeClient
{
    public partial class Form1 : Form
    {
        // The message sender.
        // It sends 'string' and gets 'DateTime' as the response.
        // Note: the 'string' is not used in this example.
        IDuplexTypedMessageSender<DateTime, string> mySender;

        public Form1()
        {
            InitializeComponent();

            // Create TCP based messaging.
            IMessagingSystemFactory aTcpMessaging = new TcpMessagingSystemFactory();

            // Create the buffered messaging.
            // If the connection is not available, 
            //the buffered messaging tries to reconnect
            // and meanwhile stores sent messages to the buffer.
            // Then, when reconnected, it sends sent messages to the receiver.
            // The following buffered messaging is based on TCP messaging
            // and can work offline 1 minute.
            IMessagingSystemFactory aBufferedMessaging = 
                new BufferedMessagingFactory(aTcpMessaging, TimeSpan.FromMinutes(1));

            IDuplexOutputChannel anOutputChannel = 
                aBufferedMessaging.CreateDuplexOutputChannel("tcp://127.0.0.1:7083/");


            // Create the message sender.
            IDuplexTypedMessagesFactory aTypedMessagesFactory = 
                    new DuplexTypedMessagesFactory();
            mySender = aTypedMessagesFactory.CreateDuplexTypedMessageSender
            <DateTime, string>();
            mySender.ResponseReceived += OnResponseReceived;

            // Attach the output channel and be able to send requests and receive
            // response messages.
            mySender.AttachDuplexOutputChannel(anOutputChannel);
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            // Correctly close the connection.
            mySender.DetachDuplexOutputChannel();
        }

        private void RequestServiceTimeButton_Click(object sender, EventArgs e)
        {
            // Invoke the request to get the current time from the service.
            mySender.SendRequestMessage("not used");
        }

        private void OnResponseReceived(object sender, 
        TypedResponseReceivedEventArgs<DateTime> e)
        {
            if (e.ReceivingError == null)
            {
                // Display the time returned from the service.
                // Note: The response does not come in the UI thread, therefore
                //       it must be transfered to UI thread.
                DateTime aTime = e.ResponseMessage;
                InvokeInUIThread(() => ServiceTimeTextBox.Text = aTime.ToString());
            }
        }

        // Helper method to invoke the given delegate
        // in the UI thread.
        private void InvokeInUIThread(Action action)
        {
            if (InvokeRequired)
            {
                Invoke(action);
            }
            else
            {
                action();
            }
        }
    }
}

And here are communicating applications:

Image 2

License

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