To use the implementation below, you must include the Eneter.Messaging.Framework.dll library into your project. (The framework is free and can be downloaded from www.eneter.net. The online help for developers can be found http://www.eneter.net/OnlineHelp/EneterMessagingFramework/Index.html.)
Service Application
The Calculator
service provides the following functionality: summation, subtraction, multiplication and dividing. Therefore the service recognizes four types of request messages. Every request message will take two numbers as the input for the calculation.
public class CalculatorInputData
{
public double Number1 { get; set; }
public double Number2 { get; set; }
}
When the service calculates numbers, it sends back the response message with the result.
public class CalculatorOutputData
{
public double Result { get; set; }
}
We also want that the service listens to request messages on one address (one input channel). (It would not be effective if every type of request message would have its own address.)
To recognize multiple message types on one address, we use the Channel Unwrapper component from Eneter.Messaging.Framework
.
The Channel Unwrapper component receives messages on one input channel, "unwraps" them and forwards to correct receivers.
In our case, the Channel Unwrapper recognizes if the incoming message is summation, subtraction, multiplication or dividing. Then it forwards the message to the correct receiver handling the requested type of calculation.
The code implementing the behavior above is very simple with Eneter.Messaging.Framework
.
using System;
namespace ServerCalculator2
{
class Program
{
static void Main(string[] args)
{
Calculator aCalculator = new Calculator();
Console.WriteLine("Calculator service started.");
aCalculator.StartCalculatorService();
}
}
}
using System;
using Eneter.Messaging.DataProcessing.Serializing;
using Eneter.Messaging.EndPoints.TypedMessages;
using Eneter.Messaging.Infrastructure.ConnectionProvider;
using Eneter.Messaging.MessagingSystems.MessagingSystemBase;
using Eneter.Messaging.MessagingSystems.TcpMessagingSystem;
using Eneter.Messaging.MessagingSystems.ThreadPoolMessagingSystem;
using Eneter.Messaging.Nodes.ChannelWrapper;
namespace ServerCalculator2
{
public class CalculatorInputData
{
public double Number1 { get; set; }
public double Number2 { get; set; }
}
public class CalculatorOutputData
{
public double Result { get; set; }
}
internal class Calculator
{
public Calculator()
{
IMessagingSystemFactory anInternalMessaging =
new ThreadPoolMessagingSystemFactory();
ISerializer aSerializer = new XmlStringSerializer();
IChannelWrapperFactory aChannelWrapperFactory =
new ChannelWrapperFactory(aSerializer);
myDuplexChannelUnwrapper =
aChannelWrapperFactory.CreateDuplexChannelUnwrapper(anInternalMessaging);
IConnectionProviderFactory aConnectionProviderFactory =
new ConnectionProviderFactory();
IConnectionProvider aConnectionProvider =
aConnectionProviderFactory.CreateConnectionProvider(anInternalMessaging);
IDuplexTypedMessagesFactory aMessageReceiverFactory =
new DuplexTypedMessagesFactory(aSerializer);
mySumReceiver = aMessageReceiverFactory.CreateDuplexTypedMessageReceiver
<CalculatorOutputData, CalculatorInputData>();
mySumReceiver.MessageReceived += SumCmd;
aConnectionProvider.Attach(mySumReceiver, "Sum");
mySubtractReceiver = aMessageReceiverFactory.CreateDuplexTypedMessageReceiver
<CalculatorOutputData, CalculatorInputData>();
mySubtractReceiver.MessageReceived += SubCmd;
aConnectionProvider.Attach(mySubtractReceiver, "Sub");
myMultiplyReceiver = aMessageReceiverFactory.CreateDuplexTypedMessageReceiver
<CalculatorOutputData, CalculatorInputData>();
myMultiplyReceiver.MessageReceived += MulCmd;
aConnectionProvider.Attach(myMultiplyReceiver, "Mul");
myDivideReceiver = aMessageReceiverFactory.CreateDuplexTypedMessageReceiver
<CalculatorOutputData, CalculatorInputData>();
myDivideReceiver.MessageReceived += DivCmd;
aConnectionProvider.Attach(myDivideReceiver, "Div");
}
public void StartCalculatorService()
{
IMessagingSystemFactory aServiceMessagingSystem =
new TcpMessagingSystemFactory();
IDuplexInputChannel aGlobalInputChannel =
aServiceMessagingSystem.CreateDuplexInputChannel("127.0.0.1:8091");
myDuplexChannelUnwrapper.AttachDuplexInputChannel(aGlobalInputChannel);
}
private void SumCmd(object sender,
TypedRequestReceivedEventArgs<CalculatorInputData> e)
{
CalculatorInputData anInputData = e.RequestMessage;
CalculatorOutputData aReturn = new CalculatorOutputData();
aReturn.Result = anInputData.Number1 + anInputData.Number2;
Console.WriteLine("{0} + {1} = {2}", anInputData.Number1,
anInputData.Number2, aReturn.Result);
mySumReceiver.SendResponseMessage(e.ResponseReceiverId, aReturn);
}
private void SubCmd(object sender, TypedRequestReceivedEventArgs
<CalculatorInputData> e)
{
CalculatorInputData anInputData = e.RequestMessage;
CalculatorOutputData aReturn = new CalculatorOutputData();
aReturn.Result = anInputData.Number1 - anInputData.Number2;
Console.WriteLine("{0} - {1} = {2}", anInputData.Number1,
anInputData.Number2, aReturn.Result);
mySubtractReceiver.SendResponseMessage(e.ResponseReceiverId, aReturn);
}
private void MulCmd(object sender, TypedRequestReceivedEventArgs
<CalculatorInputData> e)
{
CalculatorInputData anInputData = e.RequestMessage;
CalculatorOutputData aReturn = new CalculatorOutputData();
aReturn.Result = anInputData.Number1 * anInputData.Number2;
Console.WriteLine("{0} x {1} = {2}", anInputData.Number1,
anInputData.Number2, aReturn.Result);
myMultiplyReceiver.SendResponseMessage(e.ResponseReceiverId, aReturn);
}
private void DivCmd(object sender, TypedRequestReceivedEventArgs
<CalculatorInputData> e)
{
CalculatorInputData anInputData = e.RequestMessage;
CalculatorOutputData aReturn = new CalculatorOutputData();
aReturn.Result = anInputData.Number1 / anInputData.Number2;
Console.WriteLine("{0} / {1} = {2}", anInputData.Number1,
anInputData.Number2, aReturn.Result);
myDivideReceiver.SendResponseMessage(e.ResponseReceiverId, aReturn);
}
private IDuplexChannelUnwrapper myDuplexChannelUnwrapper;
private IDuplexTypedMessageReceiver<CalculatorOutputData,
CalculatorInputData> mySumReceiver;
private IDuplexTypedMessageReceiver<CalculatorOutputData,
CalculatorInputData> mySubtractReceiver;
private IDuplexTypedMessageReceiver<CalculatorOutputData,
CalculatorInputData> myMultiplyReceiver;
private IDuplexTypedMessageReceiver<CalculatorOutputData,
CalculatorInputData> myDivideReceiver;
}
}
Client Application
The client application implements a simple UI taking numbers and invoking requests for the calculation.
To send multiple message types to the Calculator
service via one output channel (because the service receives messages via one input channel (address)), the client must use the Channel Wrapper component. The Channel Wrapper component wraps outgoing request messages so that they can be unwrapped by the service when they are received.
The code implementing the client behavior is very simple too.
using System;
using System.Windows.Forms;
using Eneter.Messaging.DataProcessing.Serializing;
using Eneter.Messaging.EndPoints.TypedMessages;
using Eneter.Messaging.Infrastructure.ConnectionProvider;
using Eneter.Messaging.MessagingSystems.MessagingSystemBase;
using Eneter.Messaging.MessagingSystems.TcpMessagingSystem;
using Eneter.Messaging.MessagingSystems.ThreadMessagingSystem;
using Eneter.Messaging.Nodes.ChannelWrapper;
namespace CalculatorClient2
{
public class CalculatorInputData
{
public double Number1 { get; set; }
public double Number2 { get; set; }
}
public class CalculatorOutputData
{
public double Result { get; set; }
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
IMessagingSystemFactory anInternalMessaging =
new ThreadMessagingSystemFactory();
ISerializer aSerializer = new XmlStringSerializer();
IChannelWrapperFactory aChannelWrapperFactory =
new ChannelWrapperFactory(aSerializer);
myDuplexChannelWrapper = aChannelWrapperFactory.CreateDuplexChannelWrapper();
IConnectionProviderFactory aConnectionProviderFactory =
new ConnectionProviderFactory();
IConnectionProvider aConnectionProvider =
aConnectionProviderFactory.CreateConnectionProvider(anInternalMessaging);
IDuplexTypedMessagesFactory aCommandsFactory =
new DuplexTypedMessagesFactory(aSerializer);
mySumSender = aCommandsFactory.CreateDuplexTypedMessageSender
<CalculatorOutputData, CalculatorInputData>();
mySumSender.ResponseReceived += OnResultResponse;
aConnectionProvider.Connect(myDuplexChannelWrapper, mySumSender, "Sum");
mySubSender = aCommandsFactory.CreateDuplexTypedMessageSender
<CalculatorOutputData, CalculatorInputData>();
mySubSender.ResponseReceived += OnResultResponse;
aConnectionProvider.Connect(myDuplexChannelWrapper, mySubSender, "Sub");
myMulSender = aCommandsFactory.CreateDuplexTypedMessageSender
<CalculatorOutputData, CalculatorInputData>();
myMulSender.ResponseReceived += OnResultResponse;
aConnectionProvider.Connect(myDuplexChannelWrapper, myMulSender, "Mul");
myDivSender = aCommandsFactory.CreateDuplexTypedMessageSender
<CalculatorOutputData, CalculatorInputData>();
myDivSender.ResponseReceived += OnResultResponse;
aConnectionProvider.Connect(myDuplexChannelWrapper, myDivSender, "Div");
IMessagingSystemFactory aTcpMessagingSystem = new TcpMessagingSystemFactory();
IDuplexOutputChannel anOutputChannel =
aTcpMessagingSystem.CreateDuplexOutputChannel("127.0.0.1:8091");
myDuplexChannelWrapper.AttachDuplexOutputChannel(anOutputChannel);
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
myDuplexChannelWrapper.DetachDuplexOutputChannel();
}
private void OnResultResponse(object sender,
TypedResponseReceivedEventArgs<CalculatorOutputData> e)
{
if (e.ReceivingError == null)
{
InvokeInUIThread(() => ResultLabel.Text =
e.ResponseMessage.Result.ToString() );
}
}
private void CalculateButton_Click(object sender, EventArgs e)
{
CalculatorInputData anInputForCalculator = new CalculatorInputData();
anInputForCalculator.Number1 = double.Parse(Number1TextBox.Text);
anInputForCalculator.Number2 = double.Parse(Number2TextBox.Text);
mySumSender.SendRequestMessage(anInputForCalculator);
}
private void SubtractButton_Click(object sender, EventArgs e)
{
CalculatorInputData anInputForCalculator = new CalculatorInputData();
anInputForCalculator.Number1 = double.Parse(Number1TextBox.Text);
anInputForCalculator.Number2 = double.Parse(Number2TextBox.Text);
mySubSender.SendRequestMessage(anInputForCalculator);
}
private void MultiplyButton_Click(object sender, EventArgs e)
{
CalculatorInputData anInputForCalculator = new CalculatorInputData();
anInputForCalculator.Number1 = double.Parse(Number1TextBox.Text);
anInputForCalculator.Number2 = double.Parse(Number2TextBox.Text);
myMulSender.SendRequestMessage(anInputForCalculator);
}
private void DivideButton_Click(object sender, EventArgs e)
{
CalculatorInputData anInputForCalculator = new CalculatorInputData();
anInputForCalculator.Number1 = double.Parse(Number1TextBox.Text);
anInputForCalculator.Number2 = double.Parse(Number2TextBox.Text);
myDivSender.SendRequestMessage(anInputForCalculator);
}
private void InvokeInUIThread(Action action)
{
if (InvokeRequired)
{
Invoke(action);
}
else
{
action.Invoke();
}
}
private IDuplexChannelWrapper myDuplexChannelWrapper;
private IDuplexTypedMessageSender<CalculatorOutputData,
CalculatorInputData> mySumSender;
private IDuplexTypedMessageSender<CalculatorOutputData,
CalculatorInputData> mySubSender;
private IDuplexTypedMessageSender<CalculatorOutputData,
CalculatorInputData> myMulSender;
private IDuplexTypedMessageSender<CalculatorOutputData,
CalculatorInputData> myDivSender;
}
}
I hope you found this example useful. If you would like to read more technical details or you would need the online help, you can use
http://www.eneter.net/OnlineHelp/EneterMessagingFramework/Index.html.
If you have any questions, do not hesitate to ask me.