Friday, January 14, 2011

WPF - Messaging using MSMQ

We have been discussing messaging options for intra and inter-process communication. Message Queuing is also a messaging infrastructure. The Microsoft product for Message queuing is MSMQ. There are various other products like JMS (Java Messaging Services), Apache’s Active MQ and TIBCO’s EMS which you might consider for enterprise messaging.



Types of Queues:
There are two types of queues supported in MSMQ. They are as follows:

1. Public Queues
2. Private Queues

Enabling MSMQ services in Windows:
Before we start using MSMQ we need to install MSMQ services on the machine we expect to keep queues.



Assembly and Namespace:
MSMQ types are in System.Messaging namespace. This is available in System.Messaging.dll. In order to use these types, we need to add a reference of this assembly.



Creating Queue:
We can create a MSMQ queue using Computer Management Console.



We can specify the name of queue. Let's name it WPFTestQueue:



We can also create queue through code as follows:

private void btnCreateQueue_Click(object sender, RoutedEventArgs e)
{
//Name of queue. Preceded by . (DOT) to specify local system
string queueName = @".\private$\WPFTestQueue";

MessageQueue messageQueue = null;
if (!MessageQueue.Exists(queueName))
{
messageQueue = MessageQueue.Create(queueName);
}
}

If a queue with same name already exists, it results in System.Messaging.MessageQueueException with exception message "A queue with the same path name already exists."



The queue, once created, can be found here:



Queuing Message:
It is very simple to queue messages in MSMQ. We just need to create an object of MessageQueue and send a message to the queue. The below code is an event handler for a button click event. It is demonstrating how we can send message to the queue.

private void btnSend_Click(object sender, RoutedEventArgs e)
{
MessageQueue queue = new MessageQueue(@".\private$\WPFTestQueue");
queue.Send(this.textBox1.Text);
}

Here . (DOT) refers to the local computer. As we send message to the queue, they become available for administration in Computer Management Console.



Various useful information about the message (including the message itself) can be found by taking the properties of the message in the same Window.



We can also see the body of message:



Receiving Message from the Queue:
To receive message from the queue, we just need to specify queue name including the complete path where the queue resides. We also need to specify the format of message. Here we are sending string message.

private void btnReceive_Click(object sender, RoutedEventArgs e)
{
MessageQueue queue = new MessageQueue(@".\private$\WPFTestQueue");
queue.Formatter = new XmlMessageFormatter(new Type[] {typeof(string)});
Message msg = queue.Receive();
this.textBoxMessage.Text = msg.Body.ToString();
}

We might need to share Interface definition between sender and receiver for message type if we are planning to send more complex messages.

It must be remembered that Receive is a synchronous / blocking call. You would be glad to know that MSMQ also has an asynchronous version of Receive. It is BeginReceive. It supports the specification of a callback which might be executed when the expected message is received.

private void btnASyncReceive_Click(object sender, RoutedEventArgs e)
{
MessageQueue queue = new MessageQueue(@".\private$\WPFTestQueue");
queue.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) });

queue.BeginReceive(new TimeSpan(0, 0, 20), queue,
(IAsyncResult result) =>
{
Message message = ((MessageQueue)result.AsyncState).EndReceive(result); //queue.EndReceive(result);

this.Dispatcher.BeginInvoke(
new Action(
() =>
{
this.textBoxMessage.Text = message.Body.ToString();
}
), null);
}
);
}

Here we are using a timeout of 20 seconds. We passed the queue reference as stateObject in order to use it in the callback. By this way we are also avoiding the use of Captured variable from outside lambda. BeginReceive creates a ThreadPool thread. Since we are on a thread other than UI thread, we are using Dispatcher to copy the message to the interface. If the message is already available in the Queue, the callback would execute as soon as you call BeginReceive on the Queue.

You can use the attached project to send and receive message using MSMQ.



Taking advantage of Message Queuing Trigger Service:
MSMQ also allows us to execute an activity based on certain messages. We can peek / retrieve messages of interest and run those activities. These activities might be in the form a COM component method or an limited executable (*.exe) file.



Message Trigger Service is installed separately. You can see find that in Services.msc.




It allows you to define a set of triggers. Each trigger can have a set of rules. Each rule has conditions and associate actions.





For each message arriving to the queue, all rules in each trigger run. The trigger service should have associate (Peek, Retrieve rights on the message queue). A rule might have some conditions and an action associated.





Security & Trigger Service Account:
As apparent from the above image, Trigger Service in MSMQ 4.0 runs with Network Service account. It is required that you give Read and Execute on the Executable file.



The triggers also need to have permission so that messages can be peeked from the queue:



MSMQ Triggers service reports warning messages in the Event Viewer. The following is an example when the service could not find the executable file in the specified path.



We can also create custom view just for MSMQ related messages. In this example we are interested in messages from MSMQ and MSMQ Triggers services.



These messages would appear as follows:



Limitations for Executable file:

Being a service, MSMQ Triggers can not launch an executable which have user interaction. It seems any executable with Message loop is forbidden. This is true even when services are marked as Interactive Services. This is to avoid Shatter Attack.

http://en.wikipedia.org/wiki/Shatter_attack

This is just a forbidden tree to even mention about User interaction in Windows Vista and up. In Interactive Services MSDN mentions: Services cannot directly interact with a user as of Windows Vista. In Windows XP, it loads the application process but it doesn't bring the UI up (still shows splash screen when application is being loaded). You can verify that the application is loaded using Task Manager.

http://msdn.microsoft.com/en-us/library/ms683502%28VS.85%29.aspx

Note:
Public queues are used in a domain environment.

Download:

4 comments:

Ola S. Halvorsen said...

Thanks for the intro to MSMQ. Great stuff! Will now deep dive into the subject because this sounds exactly right for my project! :)

Muthu said...

Thanks for the article.

Sivan said...

Your Article Really helped me a lot. but when i tried Asynchronous Receive I'm not able to Use Dispatcher Class. Wont this Class work in .Net Framework 4.0???.Plz clarify my doubt and do the needful..
Thanks in advance

Muhammad Shujaat Siddiqi said...

Thanks Sivan! Can you check if the current thread in the callback has the same dispatcher?