Introduction
The article demonstrates a simple communication service in Indigo based on the MSMQ channel.
Background
A full introduction of Indigo can be found here.
Indigo uses MSMQ as the base for its Queuing Service. This article demonstrates the changes that I applied to an Indigo uniform communication code in order to establish communication service using the MSMQ mechanism.
Requirements
In order to use the code, the following prerequisites are required:
- May Indigo CTP must be installed in the machine.
- MSMQ version 3.5 Beta for "Indigo" (Found here [24 Kb]).
The code was compiled with VS 2005 Beta II.
Using the code
Creating the Queue:
The Queue must be transactional; else the message will be lost.
The code
Initializing the service:
As in all kinds of Indigo services infrastructure: COM+, Web services etc., the following stages are required in order to initialize and start the service:
- Defining the URI:
Declaring the URI to meet a private transact local queue named: �HelloWorldQueue� (Other URI instances can point to a TCP port, asmx file etc. depending on the protocol type).
- Defining the binding type:
The binding type object contains the properties of the communication. For example, the security, compression, protocol, AddressingMode, MaxRetries ,TimeToLive etc. I use the �NetProfileMsmqBinding� which is a binary optimized cross machine binding for MSMQ transportation.
Other binding types may be: �NetProfileTcpBinding�, �WsProfileBinding� etc.
- Declaring the service:
Declaring the service stage contains the following actions:
- Declaring the
ServiceHost
based on the MyHelloWorldService
class.
- Attaching the URI and the binding type (the end point) to the service.
- Opening the service in order to start listening to incoming calls.
Uri theQueueUri =
new Uri("net.msmq://localhost/private$/HelloWorldQueue");
NetProfileMsmqBinding theBinding = new NetProfileMsmqBinding();
ServiceHost<MyHelloWorldService> theMsmqService =
new ServiceHost<MyHelloWorldService>();
theMsmqService.AddEndpoint(typeof(MyHelloWorldService),
theBinding, theQueueUri);
theMsmqService.Open();
Declaring the service contract:
By applying the [ServiceContract]
attribute to the IHelloWorldService
interface, I identify that the interface IHelloWorldService
is an Indigo service contract to the external clients.
The HelloWorld
method is declared with IsOneWay = true
, meaning asynchronous mode invocation. Setting the �IsOneWay
� flag to true
and trying to return a value will cause an exception to occur due to the decoupling between the client and the server.
[ServiceContract]
public interface IHelloWorldService
{
[OperationContract(IsOneWay = true)]
void HelloWorld(string pMessage);
}
Contract implementation class
public class MyHelloWorldService : IHelloWorldService
{
public void HelloWorld(string pMessage)
{
Console.WriteLine("This is the hello world message: " + pMessage);
}
}
The client initialization
Here again unified method is used for all Indigo service types. The developer responsibilities are only to change the binding type, the URI to meet the required communication protocol, and to set the contract class.
private void SetUpMsmqClient()
{
EndpointAddress theEndPoint = new EndpointAddress(new
Uri("net.msmq://localhost/private$/HelloWorldQueue"));
NetProfileMsmqBinding theBinding = new NetProfileMsmqBinding();
mMqChannel = new ChannelFactory<IHelloWorldService>(theEndPoint, theBinding);
mHelloWorldClient = mMqChannel.CreateChannel();
mMqChannel.Error += new
EventHandler<CommunicationErrorEventArgs>(MqChannel_Error);
}
Calling the service
I used the proxy object mHelloWorldClient
in order to call the server HelloWorld
method.
mHelloWorldClient.HelloWorld ("Hello From me !!");
Points of Interest
A declarative sample of using MSMQ in Indigo services can be found here.
You may notice the similarity between WSE 3.0 messaging mechanism to Indigo services. I�m declaring the HelloWorld
method with a simple string parameter. You can use the DataContract
attribute in order to declare complex types.
For example:
[DataContract]
public class HelloWorldData
{
private string mMessage;
private DateTime mDate;
[DataMember]
public string Message
{
get {return mMessage; }
set { mMessage = value; }
}
[DataMember]
public DateTime Date
{
get {return mDate; }
set { mDate = value; }
}
}
Pay attention that in contrast to .NET remoting or web services, there is no base class that the contract implementing class must be derived from like MarshalByRef
etc. This allows greater freedom in the implementation of the contract implementing class.