A message in Microsoft Windows Message Queuing consists of a body and a set of properties. Message bodies can contain text or any form of binary information, and can be encrypted. A message, including its body and all specified properties, cannot be bigger than 4MB in size .
You can create and send messages with your MessageQueue components . Messages created in your applications can be sent to any public, private, journal, dead-letter, or transactional queue.
Sending Simple Messages
Using an instance of the MessageQueue component, you can send simple messages to a queue in as little as two lines of code. When you send a simple message, you must perform the following actions:
After you decide with which queue you want to communicate, you need to create an instance of the MessageQueue component that references the queue you want to use. Use the component's Path property to connect to the queue with which you want to communicate by the queue path, format name , or label.
Each MessageQueue component contains a series of default properties that are applied to all messages that component sends, unless you specify otherwise in an individual message. In the simplest scenario, you can send a simple message to the queue using the default properties set for the component.
You use the Send method to specify a message and send it to the queue. You can send objects, primitive data types, streams, and other kinds of data in a simple message.
The MessageQueue component takes the data you specify in the Send method's argument, persists it into a message, and sends the message to the specified queue.
You can also use the Message object to send far more complex messages to a queue. In addition, you can send messages as part of a transaction.
Set the appropriate value for the Formatter property for your component.
Use the Send method to send a simple message to your queue, specifying the message as an argument of the method.
Your code to send a simple message might look like this:
' Visual Basic ' Create a connection to the queue. Dim MessageQueue1 as New System.Messaging.MessageQueue ("YourMachine\YourQueue") ' Send an integer. MessageQueue1.Send(1) ' Send a string. MessageQueue1.Send("Hello world") // C# // Create a connection to the queue. MessageQueue mq = new System.Messaging.MessageQueue (@"YourMachine\YourQueue"); // Send an integer. mq.Send (1); // Send a string. mq.Send ("Hello world");
Sending Complex Messages
In addition to sending a simple message by specifying your message in the Send method's argument, you can gain more control over your messages by explicitly creating a Message object, rather than letting the shared Send method create and send one for you. By manipulating the properties of the resulting Message object, you can create more complex messages and exert more control over the way your messages are handled.
When you send a complex message, you must first create a connection to the queue with which you want to communicate, and then specify the data you want to send. However, as part of specifying the data to send, you create an instance of the Message class, set the properties you need, and fine-tune the delivery mechanisms before sending your message. As with simple messages, the system persists your message object and sends it to the queue you specified.
To use the Message class to send a complex message, do the following:
When you are finished, your code might look like this:
' Visual Basic Dim myMQ1 as New System.Messaging.MessageQueue (".\YourQueue") Dim newMessage as System.Messaging.Message("Hello again") newMessage.Label = "This is the label" MessageQueue1.Send(newMessage) // C# MessageQueue MyMQ1 = new MessageQueue (@".\YourQueue"); System.Messaging.Message newMessage = new System.Messaging.Message("Hello again"); newMessage.Label = "This is the label"; MyMQ1.Send (newMessage);
Sending Messages to Disconnected Queues
There are two situations in which messages cannot readily be delivered to their queues: when the machine on which the queue resides is not available, and when the domain controller needed to route your message is not available. Message Queuing enables you to handle these situations so that if you are disconnected from the network, or a necessary machine or controller is not available, you can continue to send messages. In these cases, the messages are temporarily stored on a queue on the local machine or a machine along the delivery route until either you or the necessary resources are back online.
For example, suppose you have a central queue that records orders sent by your on-the-road sales force. Members of the sales force work in disconnected mode much of the day, recording order information from customer sites, and dial in once a day to transfer all this information to the central queue. Because messages can be sent to queues when the sender is disconnected, salespeople can send messages immediately upon recording the customer's information, and the system caches those messages until the nightly call is placed.
Sending a message to a disconnected queue is almost identical to the process of sending a message to an available queue. You do not have to perform any special configuration for your component to store messages in a temporary queue when the queue to which you are sending is not available. You must be aware of two main differences:
To send a message to a disconnected queue, do the following:
You can set up your MessageQueue component to generate acknowledgement messages that tell you whether the message was successfully delivered. You can receive two main types of acknowledgement:
Within each of these scenarios, you also can receive positive or negative acknowledgement. In positive acknowledgement, you receive an acknowledgement message when your message successfully reaches its destination queue or application. In negative acknowledgement, you receive an acknowledgement message when your message fails to reach its destination queue or application. A message might fail to reach its destination if its time-out period expires or if the message cannot be authenticated.
As with most operations in Message Queuing, acknowledgements are handled via sending a new message to a queue. In this case, the acknowledgement message is sent from the target queue to a special type of queue called an Administration queue. Acknowledgement messages differ from standard messages in that they contain no attached body; only the information in the message header is of interest in an acknowledgement.
Acknowledgement messages for your application are sent to whatever queue you specify in the AdministrationQueue property, either in the DefaultPropertiestoSend class for your component instance or on the Message object. You determine the type of acknowledgement you want to receive by setting the AcknowledgeType property to one of its predetermined values.
You can check acknowledgement messages in the same way you check any message on a queue: by peeking at the acknowledgement queue or removing messages from it.
Requesting Acknowledgement for Messages
You can request positive acknowledgement, negative acknowledgement, or a combination of acknowledgement types on the messages your MessageQueue components sends.
To request acknowledgement of a message, do the following:
Table 23.1 shows how to determine the acknowledgement responses.
Table 23.1. MessageQueue Response Acknowledgements
Message Queue Journal Storage
Journal queues enable you to save copies of messages as they are processed . You can store copies of the messages you send from your computer in the local machine journal queue, or you can store copies of messages removed from a queue in that queue's journal on the server.
Journal storage can be useful if you need to resend a message at a later point. For example, suppose you send a message to a queue and then receive negative acknowledgement, reporting that it could not be delivered. Acknowledgement messages do not contain the body of the original message; instead, they give you some header information and a correlation ID that corresponds to the original message. If you have journal recording turned on, you can use this correlation ID to locate the original message in your machine's journal queue, recreate the message object, and resend it.
You can use the ReceivebyCorrelationID or the PeekbyCorrelationID methods to retrieve a message by its correlation ID. Note that several messages may have the same correlation ID, and these methods retrieve the first message in the queue with the given ID.
You should note a few caveats about journal queues:
Storing Messages in Journal Queues
You can set up the use of journal queues for sent messages in either of two ways: You can set a default property for your MessageQueue component so that all messages sent by it will use journals, or you can establish journal queue recording for individual messages you send.
To use journals for all messages sent by an instance of the MessageQueue component, do the following:
To set journal recording for an individual message, do the following:
Your code might look like this:
' Visual Basic Message1.UseJournalQueue = True // C# Message1.UseJournalQueue = true;
To set journal recording for messages removed from a queue, do the following:
Your code might look like this:
' Visual Basic MessageQueue1.UseJournalQueue = True // C# MessageQueue1.UseJournalQueue = true;
To set the maximum size for a journal queue, do the following:
Default Message Properties
When you create an instance of the MessageQueue component, you have the option of setting a series of default properties that messages sent by that component will use. This saves you time spent defining your messages, and gives you more control over the Send method without requiring you to create and configure Message objects.
Only messages that are not sent with the Message object use the DefaultPropertiestoSend values. When you send a message using the Message object, the properties of the Message object are used.
You set default message properties by setting values for the properties in the DefaultPropertiestoSend class. These default properties control features such as whether acknowledgement messages are generated and where they are sent, how your messages are encrypted and authenticated, the message priority, and the time-out period for your messages.
Setting a default priority for your messages affects the order in which they are sent to their destination queues. You set the Priority property to determine the default priority for messages your component sends. Priority ratings default to normal, with settings for lower and higher priorities.
The priority setting for a message determines where the message is placed in the queue. Messages sent with a higher priority are placed higher in the queue, and messages with a lower priority are placed lower in the queue. When the queue receives a set of messages with an identical priority setting, the messages are arranged in the queue according to the time when they were sent.
You cannot set priority on messages that are being sent to transactional queues, because the transaction itself determines the order in which messages are processed on transactional queues.
Acknowledgement and Response Properties
You can set several default properties that determine whether responses and acknowledgements will be generated for your component's messages and how these responses will be handled. The properties you can set as a default for all messaging operations include
You can determine whether copies of your outgoing messages should be stored in a journal queue by setting the UseJournalQueue property and, similarly, whether undeliverable messages should be sent to a dead-letter queue by setting the UseDeadLetterQueue property.
You can use two time- related properties to maintain better control of your messages. Both properties determine how long a message can exist in the system before it is discarded. You use the TimeToReachQueue property to specify how long a message has to try to reach its destination queue. You use the TimeToBeReceived property to specify how long the message should remain in the system, from the time it is sent until the time the destination application removes it from the queue. If either timer interval expires, Message Queuing discards the message.
When a message is discarded because of an expired timer, the Queue Manager might take additional steps:
By default, no time-out interval is set for either property. If you set a value for both properties, the value in the TimeToBeReceived property takes precedence.
Serialization is the process of taking objects and converting their state information into a form that can be stored or transported. The basic idea of serialization is that an object writes its current state, usually indicated by the value of its member variables , to persistent storage. Later, the object can be re-created when the object's state is read, or deserialized, from the storage. Serialization handles all the details of object pointers and circular object references that are used when you serialize an object.
In the message-queuing feature, serialization refers specifically to the process of converting an object or set of data into a message that can be sent to a queue, and then converting messages retrieved from the queue back into objects or data that your application can process.
A Formatter object handles message serialization in your Visual Studio .NET or .NET framework applications. When a message is sent to the queue, the formatter serializes an object into a stream that can be sent to the message queue. When reading from a queue, the formatter deserializes the message data into the Body property.
You choose the appropriate type of formatter for the kind of data you want to send and receive. Visual Studio and the .NET framework ship three predefined formatters, each designed to persist and de-persist a different type of data:
By default, an XMLMessageFormatter is created for you when you create a MessageQueue component instance and it is associated with the instance. When the Send method is called on the MessageQueue instance, the body of your message is serialized using this formatter. You do not have to write any additional code to use the formatter during a send operation.
Reading a message is slightly more complex. To use a formatter to read from the queue, you must set properties indicating how the body of the message should be handled. If you are using the XMLMessageFormatter object, you set the TargetTypes or TargetTypeNames property. If you are using the BinaryMessageFormatter object, you set a different series of properties. The ActiveXMessageFormatter object has no associated properties.
In addition to using the formatters shipped with Visual Studio and the .NET framework, you can create your own formatters if you need to work with different types of data. You can import your formatter into a project and access it in code.
You choose the formatter you want to use by setting the Formatter property for the queue, message, or MessageQueue component with which you are working.
One advantage of the XML formatter is that you can read the strings that are created when the object or data is serialized. This means that if something happens and the message cannot be de-persisted from the message queue, you can take a look at the message itself and usually fix the problem.
Another advantage is that messages serialized with this formatter do not have to be deserialized by the same Formatter object. That is, you do not need to have the same formatter class in the receiver as you do in the sender, as long as both parties know the data schema. In addition, messages serialized by the XML formatter do not necessarily have to be deserialized at all. Most browsers and other XML viewers can parse XML messages.