You can read and receive messages from the queues in your system in several ways. First, you can either receive messages from the queue or you can peek at the messages on a queue without removing them. You also can create an event handler that watches for a new message to arrive and automatically raises an event when the message arrives at the queue. The following sections explain each of these methods of working with queue messages. You need to keep several considerations in mind when reading and retrieving messages. For example, when you perform a receive operation, you might want to temporarily prevent other users from also removing messages from the queue with which you are working. You can do this by setting the DenySharedReceive property on that queue to True. This setting prevents any other users from removing messages from the same queue until you release your use of it, either through garbage collection or by calling the Close() method. Messages have a large number of properties, and filtering the properties you want to receive can enable you to focus on only the information that is relevant to you. For example, if you are not working with transactional messages, you might not want to retrieve the properties associated with transactions. In this case, you would set the MessagePropertyFilter properties IsFirstInTransaction , IsLastInTransaction , TransactionID , and TransactionStatusQueue to False. Your MessageQueue component instance would not retrieve any of the property values corresponding to these properties whenever it gets a message from a queue. When you read messages from a queue, a Formatter object is used to serialize and deserialize the message's contents as you manipulate the message. By default, an XMLMessageFormatter object is associated with any instance of the MessageQueue component you create, and you can use this to receive messages by setting a few necessary properties on it. You can also use various other types of Formatter objects that are available to you. The XMLMessageFormatter uses human-readable XML strings to persist objects and primitive data types into and out of messages. When you want to use this formatter to retrieve a message, you set a TargetTypeNames or TargetTypes property to indicate how the resulting message should be handled. You do not have to set both properties setting one or the other causes the value to be reflected immediately in the other. If you are using another Formatter object, the properties differ . Specifying Properties to Retrieve with a MessageWhen you create an instance of the MessageQueue component, you can set a series of properties to indicate what properties you want to retrieve when the component gets a message from a queue. These properties exist in a class called MessagePropertyFilter and correspond to actual properties on the Message class. When you set the value for one of these properties to True, the component retrieves the corresponding property each time a message is removed from the queue. If you do not need access to some properties in your retrieved message and want to improve performance, you can set the MessagePropertyFilter to False. Specifying the Formatter for Retrieved MessagesYou must indicate the Formatter object you want to use to retrieve a message from a queue. A formatter indicates how a message will be deserialized when it is removed from the queue. Depending on the type of formatter you use, you might need to set additional properties to specify how the formatter should proceed. By default, you use the XMLMessageFormatter for most operations. You can specify the formatter in code. In addition, you can set the formatter either on the queue or on the message. You set the formatter on the queue when you plan to access the queue's messages directly, as in the following code: ' Visual Basic Console.WriteLine(cStr(MessageQueue1.Receive.Body)) // C# Console.WriteLine(MessageQueue1.Receive.Body.ToString()); You set the formatter on the message when you plan to retrieve a queue's contents through the Message object: ' Visual Basic Message1 = MessageQueue1.Receive // C# message1 = messageQueue1.Receive; To specify the formatter programmatically, follow these steps:
For example, the following code shows how to create and configure a component that uses the XMLMessageFormatter object to retrieve a message from a public queue called MyQueue : ' Visual Basic Dim mq As System.Messaging.MessageQueue = new System.Messaging.MessageQueue(".\MyQueue") Dim formatter As System.Messaging.XmlMessageFormatter = CType(mq.Formatter, System.Messaging.XmlMessageFormatter) formatter.TargetTypeNames = new String(){"System.String"} Dim m As System.Messaging.Message = mq.Receive(New TimeSpan(0,0,3)) // C# System.Messaging.MessageQueue mq = new System.Messaging.MessageQueue(".\MyQueue"); string[] types = { "System.String" }; ((System.Messaging.XmlMessageFormatter)mq.Formatter).TargetTypeNames = types; System.Messaging.Message m = mq.Receive(new TimeSpan(0,0,3)); Receiving Messages ProgrammaticallyYou can use a synchronous method called Receive to look at the contents of a queue. When you call the Receive method on a queue, the system removes the first message from the queue and returns it to you. This message is no longer available to other components looking at the queue. You also can look at the first message on a queue without removing it from the queue. You also can receive messages asynchronously. If no messages are available on the queue when you call the Receive method, the method waits until a message arrives on the queue. You can specify a time-out period if you want the method to wait for only a specified interval. The time-out period is specified as a TimeSpan object. When you read messages from a queue, a Formatter object is used to serialize and deserialize the message's contents as you manipulate the message. There are several forms of the Receive method. The basic method has several overloads that enable you to specify things such as time-out periods. A method called MessageQueue.ReceiveById enables you to retrieve a particular message by its identifier. A method called ReceiveByCorrelationID enables you to retrieve a message by correlation ID. To receive a message programmatically, do the following:
To specify a time-out for the Receive method, use a TimeSpan object to specify the length of time that you want the method to wait. When you are finished, your code might look like this: ' Visual Basic Dim mq As System.Messaging.MessageQueue = new System.Messaging.MessageQueue(".\MyQueue") mq.Send("1","1") Dim m as System.Messaging.Message m = mq.Receive(New TimeSpan(0,0,3)) m.Formatter = new XmlMessageFormatter(new string(){"System.String, mscorlib"}) Console.WriteLine(m.Body) // C# System.Messaging.MessageQueue mq = new System.Messaging.MessageQueue(".\MyQueue"); mq.Send("1","1"); Message m = mq.Receive(new TimeSpan(0,0,3)); m.Formatter = new XmlMessageFormatter(new string[] {"System.String,mscorlib"}); Console.WriteLine(m.Body); Peeking at MessagesYou can use the Peek method to look at the first message on any queue without removing that message from the queue. This allows your component to get information from the queue without preventing other applications or components from retrieving messages they were intended to process. Peek enables you to see only the first message on the queue. Because that message is not removed from the queue when you peek at it, you cannot then peek at subsequent messages. If you want to see all the messages in a queue without removing them from the queue, you can use the GetMessages method or the GetMessagesEnumerator method. If no messages are in the queue when you call the Peek method, the method waits until a message arrives. You can specify a time-out period if you want the method to wait only a specified period of time. The time-out period is specified as a TimeSpan object. Most commonly, the time-out period will be set to either zero, in which case it checks for a message and does not wait at all, or to the default infinite setting, which waits indefinitely. You set this in code using the following syntax: ' Visual Basic msg.TimeToBeReceived = msg.InfiniteTimeout // C# msg.TimeToBeReceived = msg.InfiniteTimeout; When using dependent clients , be sure the clock on the client computer is synchronized with the clock on the server that is running Message Queuing. Otherwise, unpredictable behavior might result if you send a message whose TimeToBeReceived property is not InfiniteTimeout . To peek at messages synchronously, do the following:
For example, the following code shows how you can use the Peek method to return and display information about the first message on a queue. This example assumes that you are working on a Windows forms application that contains a label called Label1, and that you are working with a queue called MyQueue. ' Visual Basic Public Sub LookFirstMessage() Dim NewQueue As New System.Messaging.MessageQueue(".\MyQueue") Dim FirstMessage As System.Messaging.Message FirstMessage = NewQueue.Peek FirstMessage.Formatter = new XmlMessageFormatter() cType(FirstMessage.Formatter, XmlMessageFormatter).TargetTypeNames = new string(){"System.String, mscorlib"} label1.Text = CStr(FirstMessage.Label) End Sub // C# public void LookFirstMessage() { System.Messaging.MessageQueue newQueue = new System.Messaging.MessageQueue(".\MyQueue"); System.Messaging.Message firstMessage; string[] types = { "System.String, mscorlib" }; System.Messaging.Message firstMessage; firstMessage = newQueue.Peek(); firstMessage.Formatter = new XmlMessageformatter(types); Label1.Text=((string)firstMessage.Label); } Asynchronous Message ProcessingYou can retrieve messages asynchronously if you want to retrieve messages without tying up your application's processing. In asynchronous message processing, methods start tasks and then return immediately to the caller without waiting for a result. The application can continue to do what it was originally doing while the task is completed. When the task completes, the server can notify the application that the message was successfully processed . There are two types of asynchronous messaging operations: receiving messages asynchronously and peeking at messages asynchronously. When you retrieve a message asynchronously, you use the BeginReceive method and the EndReceive method to mark the beginning and end of the operation. The actions that occur are as follows :
After the completed event is received, you call the EndReceive method to complete the operation. Within the end call, you might access the message or retrieve it by accessing the ReceiveCompletedEventArgs class. You can access the IAsyncResult object throughout the lifetime of the operation, but typically you do not use it until EndReceive is called. However, if you start several asynchronous operations, you can place their IAsyncResult values in an array and specify whether to wait for all operations or any individual operation to complete. In this case, you use the AsyncWaitHandle property of the IAsyncResult object to identify completed operations. Peeking, like receiving, uses two methods called BeginPeek and EndPeek to bracket the beginning and end of the asynchronous operation. BeginPeek returns immediately and raises an event called PeekCompleted when a message becomes available. Like ReceiveCompleted , this event returns an IAsyncResult object you can manipulate for information about the operation. In addition, both asynchronous receive and peek operations can use a time-out period to specify how long you want to wait for a message to become available. To do so, you use an overloaded form of either method to pass a TimeSpan object that indicates the time to wait. The ReceiveCompleted or PeekCompleted event is raised if the time-out period expires , but the IsCompleted property on the IAsyncResult object is set to False to indicate that a message was not dealt with. You can receive notification when your asynchronous receive or peek operation completes successfully in either of two ways:
When you use event notification, you create a method that handles your message processing and returns a notification when the processing completes. You then call the method that begins the asynchronous processing. The system creates the event handlers for you automatically when you double-click your MessageQueue component in the Designer. In the event-notification scenario, BeginPeek or BeginReceive returns a single message and then stops processing. You must call BeginPeek or BeginReceive again for each message you want to retrieve. An alternative way to process messages asynchronously is to use a callback. A callback identifies a delegate you want to associate with your BeginPeek or BeginReceive operations. In this scenario, the delegate continues to watch for new event notification after each message is processed. |