Recipe20.4.Using Message Queues on a Local Workstation


Recipe 20.4. Using Message Queues on a Local Workstation

Problem

You need a way to disconnect two components of your application (like a web service endpoint and processing logic) so that the first component has to worry about only formatting the instructions and the bulk of the processing occurs in the second component.

Solution

Use the MQWorker class shown here in both the first and second components to write and read messages to and from a message queue. MQWorker uses the local message-queuing services to do this. The queue pathname is supplied in the constructor, and the existence of the queue is checked in the SetUpQueue method.

 class MQWorker {     private string _mqPathName;     MessageQueue _queue = null;     public MQWorker(string queuePathName)     {         if (string.IsNullOrEmpty(queuePathName)             throw new ArgumentNullException("queuePathName");         _mqPathName = queuePathName;         SetUpQueue( );         } 

SetUpQueue creates a message queue of the supplied name using the MessageQueue class if none exists. It accounts for the scenario in which the message-queuing services are running on a workstation computer. In that situation, it makes the queue private, as that is the only type of queue allowed on a workstation.

 private void SetUpQueue( ) {     // See if the queue exists, create it if not.     if (!MessageQueue.Exists(_mqPathName))     {         try         {             _queue = MessageQueue.Create(_mqPathName);         }         catch (MessageQueueException mqex)         {             // See if we are running on a workgroup computer.             if (mqex.MessageQueueErrorCode ==                MessageQueueErrorCode.UnsupportedOperation)             {                 string origPath = _mqPathName;                 // Must be a private queue in workstation mode.                 int index = _mqPathName.ToLower( ).IndexOf("private$");                 if (index == -1)                 {                     // Get the first \.                     index = _mqPathName.IndexOf(@"\");                     // Insert private$\ after server entry.                     _mqPathName = _mqPathName.Insert(index + 1, @"private$\");                     if (!MessageQueue.Exists(_mqPathName))                         _queue = MessageQueue.Create(_mqPathName);                     else                         _queue = new MessageQueue(_mqPathName);                 }             }         }    }     else     {         _queue = new MessageQueue(_mqPathName);     } } 

The SendMessage method sends a message to the queue set up in the constructor. The body of the message is supplied in the body parameter, and then an instance of System.Messaging.Message is created and populated. The BinaryMessageFormatter is used to format the message, as it enables larger volumes of messages to be sent with fewer resources than does the default XmlMessageFormatter. Messages are set to be persistent by setting the Recoverable property to true. Finally, the Body is set and the message is sent.

 public void SendMessage(string label, string body) {     if (_queue != null)     {         Message msg = new Message( );         // Label our message.         msg.Label = label;         // Override the default XML formatting with binary         // as it is faster (at the expense of legibility while debugging).         msg.Formatter = new BinaryMessageFormatter( );         // Make this message persist (causes message to be written         // to disk).         msg.Recoverable = true;         msg.Body = body;         _queue.Send(msg);     } } 

The ReadMessage method reads messages from the queue set up in the constructor by creating a Message object and calling its Receive method. The message formatter is set to the BinaryMessageFormatter for the Message, since that is how we write to the queue. Finally, the body of the message is returned from the method.

     public string ReadMessage( )     {      Message msg = null;      msg = _queue.Receive( );      msg.Formatter = new BinaryMessageFormatter( );      return (string)msg.Body;     } } 

To show how the MQWorker class is used, the following example creates an MQWorker. It then sends a message (a small blob of XML) using SendMessage, then retrieves it using ReadMessage:

 // NOTE: Message Queue services must be set up for this to work. // This can be added in Add/Remove Windows Components. // This is the right syntax for workstation queues. //MQWorker mqw = new MQWorker(@".\private$\MQWorkerQ"); MQWorker mqw = new MQWorker(@".\MQWorkerQ"); string xml = "<MyXml><InnerXml location=\"inside\"/></MyXml>"; Console.WriteLine("Sending message to message queue: " + xml); mqw.SendMessage("Message Label",xml); // This could also be in a separate component. string retXml = mqw.ReadMessage(); Console.WriteLine("Read message from message queue: " + retXml); 

Discussion

Message queues are very useful when you are attempting to distribute the processing load for scalability purposes. Without question, using a message queue adds overhead to the processing, as the messages must travel through the infrastructure of MSMQ, overhead would not incur without it. One benefit is that MSMQ allows your application to spread out across multiple machines, so there can be a net gain in production. Another advantage is that this supports reliable asynchronous handling of the messages so that the sending side can be confident that the receiving side will get the message without the sender having to wait for confirmation. The Message Queue services are not installed by default, but can be installed through the Add/ Remove Windows Components applet in Control Panel. Using a message queue to buffer your processing logic from high volumes of requests (such as in the web service scenario presented earlier) can lead to more stability and ultimately can produce more throughput for your application through using multiple reader processes on multiple machines.

See Also

See the "Message Class" and "MessageQueue Class" topics in the MSDN documentation.



C# Cookbook
Secure Programming Cookbook for C and C++: Recipes for Cryptography, Authentication, Input Validation & More
ISBN: 0596003943
EAN: 2147483647
Year: 2004
Pages: 424

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net