Search This Blog

Saturday, March 23, 2013

Synchronous Client Service Communication

Summary: Example showing how to implement synchronous request-response communication between applications.


The source code for this example can be downloaded from here. To compile the example you need to add the eneter library among references.

Introduction

The example bellow demonstrates a communication scenario where the client application sends a message to the service application and waits for the response.
It means the client application does not continue after the sending but is blocked until the response is received or the timeout is exceeded.

To demonstrates this scenario the example implements a simple service application calculating two numbers and a simple client application using the service to calculate numbers. When the client sends the request it waits until the calculation result is received from the service.
The communication between applications is based on Websockets but you can use any other protocol or transportation mechanism e.g. TCP, SharedMemory, ...


The example uses Eneter Messaging Framework that makes the whole communication very simple.
(The framework is free for non-commercial use and can be downloaded from http://www.eneter.net/ProductDownload.htm.
More detailed technical info can be found at technical info.)


Client Application

The client is a simple application allowing users to enter numbers and then send the calculation request to the service. Once the message is sent the client waits until the result is received.

using System;
using System.Windows.Forms;
using Eneter.Messaging.EndPoints.TypedMessages;
using Eneter.Messaging.MessagingSystems.MessagingSystemBase;
using Eneter.Messaging.MessagingSystems.WebSocketMessagingSystem;

namespace CalculatorClientSync
{
    public partial class Form1 : Form
    {
        // Request message.
        public class RequestMessage
        {
            public int Number1 { get; set; }
            public int Number2 { get; set; }
        }

        // Response message.
        public class ResponseMessage
        {
            public int Result { get; set; }
        }

        private ISyncDuplexTypedMessageSender<ResponseMessage, RequestMessage> mySender;

        public Form1()
        {
            InitializeComponent();

            OpenConnection();
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            CloseConnection();
        }

        private void OpenConnection()
        {
            // Create the synchronous message sender.
            // It will wait max 5 seconds for the response.
            // To wait infinite time use TimeSpan.FromMiliseconds(-1) or
            // default constructor new DuplexTypedMessagesFactory()
            IDuplexTypedMessagesFactory aSenderFactory =
                new DuplexTypedMessagesFactory(TimeSpan.FromSeconds(5));
            mySender = aSenderFactory.CreateSyncDuplexTypedMessageSender<ResponseMessage, RequestMessage>();

            // Use Websocket for the communication.
            // If you want to use TCP then use TcpMessagingSystemFactory().
            IMessagingSystemFactory aMessaging = new WebSocketMessagingSystemFactory();
            IDuplexOutputChannel anOutputChannel =
                aMessaging.CreateDuplexOutputChannel("ws://127.0.0.1:8099/Calculator/");

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

        private void CloseConnection()
        {
            // Detach input channel and stop listening to response messages.
            mySender.DetachDuplexOutputChannel();
        }

        private void CalculateBtn_Click(object sender, EventArgs e)
        {
            // Create the request message.
            RequestMessage aRequest = new RequestMessage();
            aRequest.Number1 = int.Parse(Number1TextBox.Text);
            aRequest.Number2 = int.Parse(Number2TextBox.Text);

            // Send request to the service to calculate 2 numbers.
            // It waits until the response is received.
            ResponseMessage aResponse = mySender.SendRequestMessage(aRequest);

            // Display the result.
            ResultTextBox.Text = aResponse.Result.ToString();
        }
    }
}


Service Application

The service is a simple console application listening to requests to calculate numbers. When the request is received it calculates numbers and sends back the result. The implementation is very simple.


using System;
using Eneter.Messaging.EndPoints.TypedMessages;
using Eneter.Messaging.MessagingSystems.MessagingSystemBase;
using Eneter.Messaging.MessagingSystems.WebSocketMessagingSystem;

namespace CalculatorService
{
    // Request message.
    public class RequestMessage
    {
        public int Number1 { get; set; }
        public int Number2 { get; set; }
    }

    // Response message.
    public class ResponseMessage
    {
        public int Result { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // Create message receiver.
            IDuplexTypedMessagesFactory aReceiverFactory = new DuplexTypedMessagesFactory();
            IDuplexTypedMessageReceiver<ResponseMessage, RequestMessage> aReceiver =
                aReceiverFactory.CreateDuplexTypedMessageReceiver<ResponseMessage, RequestMessage>();

            // Subscribe to process request messages.
            aReceiver.MessageReceived += OnMessageReceived;

            // Use WebSocket for the communication.
            // Note: You can also other messagings. E.g. TcpMessagingSystemFactory
            IMessagingSystemFactory aMessaging = new WebSocketMessagingSystemFactory();
            IDuplexInputChannel anInputChannel =
                aMessaging.CreateDuplexInputChannel("ws://127.0.0.1:8099/Calculator/");

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

            Console.WriteLine("The calculator service is running. Press ENTER to stop.");
            Console.ReadLine();

            // Detach the input channel to stop listening.
            aReceiver.DetachDuplexInputChannel();
        }

        private static void OnMessageReceived(object sender, TypedRequestReceivedEventArgs<RequestMessage> e)
        {
            // Calculate numbers.
            ResponseMessage aResponseMessage = new ResponseMessage();
            aResponseMessage.Result = e.RequestMessage.Number1 + e.RequestMessage.Number2;

            Console.WriteLine("{0} + {1} = {2}", e.RequestMessage.Number1, e.RequestMessage.Number2, aResponseMessage.Result);

            // Send back the response message.
            var aReceiver = (IDuplexTypedMessageReceiver<ResponseMessage, RequestMessage>)sender;
            aReceiver.SendResponseMessage(e.ResponseReceiverId, aResponseMessage);
        }
    }
}

2 comments:

  1. Whre do i set waiting for ressponse timeout for client ?
    Thanks.

    ReplyDelete
    Replies
    1. Hi Bukan, the timeout can be set in the constructor of the DuplexTypedMessagesFactory.

      E.g. in the client application on line 45 I set it to 5 seconds. You can provide there your value.

      Delete