Summary: A simple example showing how to implement a service listening to TCP, HTTP and Named Pipe at the same time.
Introduction
The example below implements a simple service that is able to receive requests via TCP, HTTP and Named Pipe. Therefore, the service can be available for clients using different communication. E.g. Windows Phone 7 environment supports only HTTP.
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.)
Multiple Listening
To implement the multiple listener, we will use the Dispatcher component from the Eneter Messaging Framework.
The Dispatcher receives messages from all attached input channels and forwards them to all attached output channels.
In our scenario, the dispatcher will have three input channels (TCP, HTTP and Named Pipe) and only one output channel (local channel to the message receiver).
So, if a message is received e.g. via the TCP input channel, the dispatcher will forward it through the output channel to the typed message receiver. The typed message receiver then notifies the user code implementing the service.
Multiple Listening Service Application
The service is implemented as a simple console application. The most important part is using of the dispatcher component for the multiple listening (TCP, HTTP and Named Pipe).
Since the service listens also to HTTP, you must execute it under sufficient user rights. (I recommend administrator for the debug purposes.)
The whole implementation is very simple.
using System;
using Eneter.Messaging.EndPoints.TypedMessages;
using Eneter.Messaging.MessagingSystems.HttpMessagingSystem;
using Eneter.Messaging.MessagingSystems.MessagingSystemBase;
using Eneter.Messaging.MessagingSystems.NamedPipeMessagingSystem;
using Eneter.Messaging.MessagingSystems.SynchronousMessagingSystem;
using Eneter.Messaging.MessagingSystems.TcpMessagingSystem;
using Eneter.Messaging.Nodes.Dispatcher;
namespace MultiReceivingService
{
public class RequestData
{
public int Number1 { get; set; }
public int Number2 { get; set; }
}
class Program
{
private static IDuplexTypedMessageReceiver<int, RequestData> myReceiver;
static void Main(string[] args)
{
IMessagingSystemFactory aLocalMessaging =
new SynchronousMessagingSystemFactory();
IDuplexInputChannel aLocalInputChannel =
aLocalMessaging.CreateDuplexInputChannel("MyLocalAddress");
IDuplexTypedMessagesFactory aTypedMessagesFactory =
new DuplexTypedMessagesFactory();
myReceiver = aTypedMessagesFactory.CreateDuplexTypedMessageReceiver
<int, RequestData>();
myReceiver.MessageReceived += OnMessageReceived;
myReceiver.AttachDuplexInputChannel(aLocalInputChannel);
IMessagingSystemFactory anHttpMessaging = new HttpMessagingSystemFactory();
IDuplexInputChannel anHttpInputChannel =
anHttpMessaging.CreateDuplexInputChannel
("http://127.0.0.1:8035/MyService/");
IMessagingSystemFactory aTcpMessaging = new TcpMessagingSystemFactory();
IDuplexInputChannel aTcpInputChannel =
aTcpMessaging.CreateDuplexInputChannel("tcp://127.0.0.1:8036/");
IMessagingSystemFactory aPipeMessaging =
new NamedPipeMessagingSystemFactory();
IDuplexInputChannel aPipeInputChannel =
aPipeMessaging.CreateDuplexInputChannel("net.pipe://127.0.0.1/MyService");
IDuplexDispatcherFactory aDispatcherFactory =
new DuplexDispatcherFactory(aLocalMessaging);
IDuplexDispatcher aDispatcher = aDispatcherFactory.CreateDuplexDispatcher();
aDispatcher.AddDuplexOutputChannel("MyLocalAddress");
aDispatcher.AttachDuplexInputChannel(anHttpInputChannel);
Console.WriteLine("Listening to HTTP.");
aDispatcher.AttachDuplexInputChannel(aTcpInputChannel);
Console.WriteLine("Listening to TCP.");
aDispatcher.AttachDuplexInputChannel(aPipeInputChannel);
Console.WriteLine("Listening to Named Pipe.");
Console.WriteLine("To stop the service press enter ...");
Console.ReadLine();
aDispatcher.DetachDuplexInputChannel();
}
static void OnMessageReceived(object sender,
TypedRequestReceivedEventArgs<RequestData> e)
{
if (e.ReceivingError == null)
{
int aResult = e.RequestMessage.Number1 + e.RequestMessage.Number2;
Console.WriteLine("{0} + {1} = {2}",
e.RequestMessage.Number1, e.RequestMessage.Number2, aResult);
myReceiver.SendResponseMessage(e.ResponseReceiverId, aResult);
}
}
}
}
Client Application
The client is a simple Windows Form application using the service to calculate two numbers provided by the user. The client can communicate with the service via TCP, HTTP or Named Pipe.
Since the service application is executed under administrator user rights, the named pipe client must also be executed under same rights. (HTTP and TCP clients do not have to run under administrator user rights.)
using System;
using System.Windows.Forms;
using Eneter.Messaging.EndPoints.TypedMessages;
using Eneter.Messaging.MessagingSystems.MessagingSystemBase;
using Eneter.Messaging.MessagingSystems.TcpMessagingSystem;
namespace TcpClient
{
public partial class Form1 : Form
{
public class RequestData
{
public int Number1 { get; set; }
public int Number2 { get; set; }
}
private static IDuplexTypedMessageSender<int, RequestData> mySender;
public Form1()
{
InitializeComponent();
IMessagingSystemFactory aTcpMessaging = new TcpMessagingSystemFactory();
IDuplexOutputChannel anOutputChannel =
aTcpMessaging.CreateDuplexOutputChannel("tcp://127.0.0.1:8036/");
IDuplexTypedMessagesFactory aTypedMessagesFactory =
new DuplexTypedMessagesFactory();
mySender = aTypedMessagesFactory.CreateDuplexTypedMessageSender
<int, RequestData>();
mySender.ResponseReceived += OnResponseReceived;
mySender.AttachDuplexOutputChannel(anOutputChannel);
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
mySender.DetachDuplexOutputChannel();
}
private void CalculateButton_Click(object sender, EventArgs e)
{
RequestData aRequestData = new RequestData();
aRequestData.Number1 = int.Parse(Number1TextBox.Text);
aRequestData.Number2 = int.Parse(Number2TextBox.Text);
mySender.SendRequestMessage(aRequestData);
}
private void OnResponseReceived(object sender,
TypedResponseReceivedEventArgs<int> e)
{
if (e.ReceivingError == null)
{
InvokeInUIThread(() => ResultTextBox.Text = e.ResponseMessage.ToString());
}
}
private void InvokeInUIThread(Action action)
{
if (InvokeRequired)
{
Invoke(action);
}
else
{
action();
}
}
}
}
And here are the communicating applications:
CodeProject