Now let's create a sample application. Create a Windows application and add controls to the form so that the final form looks like Figure 21-3.
Figure 21-3: Message Queue Manager form
The Create Queue button reads the name from New Queue Name text box and creates a new queue on the server. Listing 21-4 shows a Create Queue button event handler, which reads the queue name from a text box and creates a private queue. It also sets the priority of the queue based on the user's option selected on the form. The Transactional check box is responsible for creating a transactional queue.
Listing 21-4: Creating a Queue
Private Sub CreateQueueBtn_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles CreateQueueBtn.Click Dim str As String = String.Empty Dim trn As Boolean = False ' If transactional type is true If CheckBox1.Checked Then trn = True End If ' If queue is private If RadioButton1.Checked Then str = ".\Private$\" End If str += TextBox1.Text If Not MessageQueue.Exists(str) Then currentQueue = MessageQueue.Create(str, trn) If currentQueue Is Nothing Then ' Set priority If RadioButton4.Checked Then currentQueue.BasePriority = _ Convert.ToInt16(MessagePriority.High) ElseIf RadioButton5.Checked Then currentQueue.BasePriority = _ Convert.ToInt16(MessagePriority.Low) Else currentQueue.BasePriority = 0 End If ListBox1.Items.Add(TextBox1.Text) ListBox1.Update() End If End If End Sub
The Delete Queue button deletes the queue from the server (see Listing 21-5).
Listing 21-5: Deleting a Queue
Private Sub DeleteQueBtn_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles DeleteQueBtn.Click Dim str As String = String.Empty ' If queue is private If RadioButton1.Checked Then str = ".\Private$\" End If str += TextBox2.Text ' Create and connect to a public Message Queuing queue. If MessageQueue.Exists(str) Then MessageQueue.Delete(str) End If End Sub
The Queue Properties button simply returns the current queue properties (see Listing 21-6).
Listing 21-6: Getting a Queue's Properties
Private Sub QuePropsBtn_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles QuePropsBtn.Click Dim props As String = "Format Name: " + currentQueue.FormatName props += ", Base Priority:" + currentQueue.BasePriority.ToString() props += ", Create Time:" + currentQueue.CreateTime.ToString() props += ", ID:" + currentQueue.Id.ToString() props += ", Path:" + currentQueue.Path.ToString() props += ", Max Size:" + currentQueue.MaximumQueueSize.ToString() props += ", Transaction:" + currentQueue.Transactional.ToString() MessageBox.Show(props) End Sub
The simplest way to create a MessageQueue instance is just drag a queue from the Server Explorer to a form in the form designer. This action adds a MessageQueue component to the form.
But most of the time you'll be creating a MessageQueue instance programmatically. For that, you create a MessageQueue object and set its path. For example, the following code creates a MessageQueue instance programmatically:
Dim mq = new MessageQueue() mq.Path = ".\mcbQueue"
Alternatively, you can also pass the path in the MessageQueue constructor as follows:
Dim mq = new MessageQueue(".\mcbQueue")
You can create a MessageQueue instance from a path, from a format name, or from a label. Each of these methods has their advantages. For example, in XML Web services, the format name method gives you better performance than the path method. When a queue is disconnected, the path method won't work. You have to use the format method.
The path of queue takes the form servername\queuename. Each type of queue has a unique path. Actually, the path is the combination of machine name and queue name of a queue. You can use the MachineName and QueueName properties of MessageQueue and combine them to get the path of a queue.
Table 21-3 describes the paths for different types of queues.
QUEUE TYPE | PATH |
---|---|
Public queue | MachineName\QueueName |
Private queue | MachineName\Private$\QueueName |
Journal queue | MachineName\QueueName\Journal$ |
Machine journal queue | MachineName\Journal$ |
Machine dead-letter queue | MachineName\Deadletter$ |
Machine transactional dead-letter queue | MachineName\XactDeadletter$ |
Tip | The dot (.) represents the current machine in a path. For example, MessageQueue1.Path=".\mcbQueue" represents the mcbQueue queue on the current machine. |
The following code uses the path of the queue:
MessageQueue1.Path=".\mcbQueue"
You can use format names to indicate whether a queue is public or private. The FORMATNAME:PUBLIC=QueueGUID, FORMATNAME:PRIVATE=MachineGUID\QueueNumber, and FORMATNAME:PUBLIC=QueueGUID;JOURNAL names represent public, private, and journal queues, respectively.
The following code sets the path of the queue as a public queue using format names:
MessageQueue1.Path = "FORMATNAME:PUBLIC=queueGUID"
You can also use a label name to refer to a queue. The Label property of MessageQueue represents the label of a queue:
MessageQueue1.Path="LABEL:mcbQueue"
The Send method of MessageQueue is responsible for sending a message to the queue. Using these forms, you can even specify the type of MSMQ transaction. The Send message takes the first argument of type Object, which can be a Message object, a text string, or any other message. The Send method has six overloaded forms:
Overloads Public Sub Send(Object) Overloads Public Sub Send(Object, _ MessageQueueTransaction) Overloads Public Sub Send(Object, _ MessageQueueTransactionType) Overloads Public Sub Send(Object, String) Overloads Public Sub Send(Object, String, _ MessageQueueTransaction) Overloads Public Sub Send(Object, String, _ MessageQueueTransactionType)
The Receive method receives the first message in the queue and removes it from the queue. If there's no message available in the queue, you can even specify a time span, and the method will wait for that interval or until the next message is available in the queue. The Receive method has six overloaded forms:
Public Overloads Function Receive() As Message Overloads Public Function Receive _ (MessageQueueTransaction) As Message Overloads Public Function Receive _ (MessageQueueTransactionType) As Message Overloads Public Function Receive(TimeSpan) As Message Overloads Public Function Receive(TimeSpan, _ MessageQueueTransaction) As Message Overloads Public Function Receive(TimeSpan, _ MessageQueueTransactionType) As Message
Both the Send and Receive methods take an argument of type MessageQueueTransactionType enumeration, which specify the type of transaction. It can be Automatic, None, or Single. The None type transaction represents that the operation will not be transactional. The Single option is for single internal transactions, and the Automatic type is used for Microsoft Transaction Server (MTS) or COM+ 1.0 services.
Before discussing messaging any further, let's create a simple messaging application using VS .NET. In this application, you'll send and receive messages using a Windows application.
First, add two Label controls, two TextBox controls, two Button controls, and a DataGrid control to the form. Second, set the second TextBox control's Multiline property to true. The final application looks like Figure 21-4. As you can see, you'll read the title and body of a message. The Send Message button will send message to the queue, and the Receive Messages button will read all the messages from the queue and display them in the DataGrid control.
Figure 21-4: A simple messaging application
After creating a Windows application, open the Server Explorer and expand the Message Queues node. Right-click the Private Queues node and click the Create Queues menu item. Type mcbQ in the text box and then click OK. Don't select the Transactional check box. To verify the action, you should now have a mcbQ queue listed under your Private Queues node.
Now drag the mcbQ queue to the form. This action adds a reference to the System.Messaging namespace and adds an object of type MessageQueue called MessageQueue1.
Finally, the only thing you need to do is add code to send and receive messages. Listing 21-7 shows the code of the Send Message button click event handler. As you can see, the code simply reads the title and body text, creates a Message object, sets its Label and Body properties, and then calls the MessageQueue.Send method.
Listing 21-7: Sending Messages to a Queue
Private Sub SendMsgBtn_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles SendMsgBtn.Click Dim msg As System.Messaging.Message = _ New System.Messaging.Message(titleTextBox.Text) msg.Label = titleTextBox.Text msg.Body = bodyTextBox.Text MessageQueue1.Send(msg) End Sub
Note | We'll discuss the Message class in more detail in the following sections. |
Listing 21-8 reads messages from a queue and adds them to the DataGrid control. As you can see, this code calls the GetAllMessages method of MessageQueue, which returns an array of Message objects. After that it simply reads the Label and Body properties of a Message and adds them to a DataTable. This DataTable is bound to the DataGrid control to display the results.
Listing 21-8: Receiving Messages from a Queue
Private Sub RecMsgBtn_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles RecMsgBtn.Click ' Create a DataTable in memory Dim dtTable As New DataTable() dtTable.Columns.Add("Title") dtTable.Columns.Add("Message Body") Dim messages() As System.Messaging.Message messages = MessageQueue1.GetAllMessages() ' Need a formatter to get the text of the message body. Dim stringFormatter As System.Messaging.XmlMessageFormatter = _ New System.Messaging.XmlMessageFormatter(New String() _ {"System.String"}) Dim index As Integer Dim msg As System.Messaging.Message For index = 0 To messages.Length - 1 messages(index).Formatter = stringFormatter msg = messages(index) Dim row As DataRow = dtTable.NewRow() row(0) = msg.Label row(1) = msg.Body.ToString() dtTable.Rows.Add(row) Next DataGrid1.DataSource = dtTable End Sub
Now, run the application, enter the title and body of the messages, and click Send Message to send messages to the queue. When you're done sending messages, click the Receive Messages button to read all the messages from the queue (see Figure 21-5).
Figure 21-5: Messaging application in action