Using Message Queuing


Email is designed for human-to-human communication. Microsoft Message Queuing, on the other hand, is designed for application-to-application communication. You can use Microsoft Message Queuing to reliably send messages from one computer to another.

Imagine, for example, that you have a central server that stores product orders. The other servers in your organization can use Microsoft Message Queuing to send orders to this central computer. If, for whatever reasons the central computer fails, the messages will not be lost. The orders will wait patiently in the queue until the central server is available again.

You can send simple and complex messages with Microsoft Message Queuing with the same ease. You can use Microsoft Message Queuing to send strings, numbers , or complex custom Visual Basic classes.

Microsoft Message Queuing supports such advanced functionality as message priorities, transactional messages, message acknowledgements, and message encryption and authentication.

Message Queuing Versus XML Web Services

So, when should you use Message Queuing and when should you use Web Services?

Both Message Queuing and Web Services facilitate application-to-application communication. You can use either technology to send complex messages over a network.

However, Web Services, unlike Message Queuing, is based on open standards like HTTP and SOAP. A Web Service facilitates application-to-application communication even when the applications are built on different platforms and operating systems.

In some ways, however, Microsoft Message Queuing is a more mature technology. Microsoft Message Queuing, unlike Web Services, has built-in support for such things as authentication, message priorities, and guaranteed message delivery.

There is no reason why you can't combine the functionality of Web Services and Message Queuing. For example, you could create a Web Service that sends and receives messages from Microsoft Message Queuing.


Microsoft Message Queuing is a complex topic. All aspects of this technology aren't covered here; however, in the following sections, you'll be provided with an overview of the basic operations that you can perform with Message Queuing from an ASP.NET page using the .NET messaging classes.

Configuring Microsoft Message Queuing

Microsoft Message Queuing is an optional component of Windows 2000 Server. Before you can use any of the messaging classes described in this section, you'll need to install it. See your Windows Help documentation for detailed installation instructions.

CAUTION

To take advantage of all the features of Microsoft Message Queuing, you'll need to configure Message Queuing on a server that is part of a Windows domain.


After you install Microsoft Message Queuing, you must complete one more step. You must check that your application is configured to have access to the System.Messaging assembly. You can configure the assemblies available to your application in either the machine.config file or a Web.Config file located in a particular application directory. In either case, you must add a reference to the System.Messaging assembly in the <assemblies> configuration section.

The Web.Config file in Listing 26.6 explicitly adds the System.Messaging assembly to your application.

Listing 26.6 Web.Config
[View full width]
 <configuration>   <system.web>     <compilation>       <assemblies>       <add         assembly="System.Messaging, Version=1.0.2411.0, Culture=neutral, graphics/ccc.gif PublicKeyToken=b03f5f7f11d50a3a" />       </assemblies>     </compilation>   </system.web> </configuration> 

The C# version of this code can be found on the CD-ROM.

CAUTION

Most likely, you will have a different version of the System.Messaging assembly installed on your computer. In that case, the Web.Config file described in this section won't work. To verify the version and public key token of your System.Messaging assembly, execute the following statement from a command prompt:

 
 gacutil /l 

This command lists the properties of every assembly installed in your server's global assembly cache.


Working with Message Queues

A queue is a temporary storage mechanism for messages while they are in transit from one application to another. Applications can send messages to a queue and receive messages from a queue. For example, you might want to create a queue called OrdersQueue that is used to transmit product orders from a Web server to a central orders database server.

Microsoft Message Queuing supports two types of user queues: public queues, which are available to applications on every server in a domain, and private queues, which are available only to applications on the local server.

Microsoft Message Queuing is also configured with several system queues, such as the dead-letter queues and journal queues. A dead-letter queue is used to hold messages that could not be successfully delivered. A journal queue is used to keep copies of messages.

Retrieving a List of Queues

The classes in the System.Messaging namespace include a number of different methods for retrieving lists of existing queues. The page in Listing 26.7 uses one of these methods , the GetPublicQueues() method, to retrieve a list of all the public queues on the network.

Listing 26.7 GetPublicQueues.aspx
 <%@ Import Namespace="System.Messaging" %> <Script runat="Server"> Sub Page_Load   dgrdQueues.DataSource = MessageQueue.GetPublicQueues()   dgrdQueues.DataBind() End Sub </Script> <html> <head><title>GetPublicQueues.aspx</title></head> <body> <asp:DataGrid   id="dgrdQueues"   Runat="Server" /> </body> </html> 

The C# version of this code can be found on the CD-ROM.

The first line in Listing 26.7 is used to import the System.Messaging namespace. Next, in the Page_Load subroutine, an array of public queues is retrieved from the GetPublicQueues() method and assigned to a DataGrid .

Creating a New Queue

You can create new public and private queues. In either case, you use the CreateQueue() method of the MessageQueue class.

The page in Listing 26.8 creates a new public queue named OrdersQueue .

Listing 26.8 CreatePublicQueue.aspx
 <%@ Import Namespace="System.Messaging" %> <Script runat="Server"> Sub Page_Load   If Not MessageQueue.Exists( ".\OrdersQueue" ) Then     MessageQueue.Create( ".\OrdersQueue" )   End If End Sub </Script> <html> <head><title>CreatePublicQueue.aspx</title></head> <body> <h2>OrdersQueue Created!</h2> </body> </html> 

The C# version of this code can be found on the CD-ROM.

In Listing 26.8, the OrdersQueue is created with the string .\OrdersQueue . The period is shorthand for the name of the local machine. Instead of using a period, you can specify a machine name .

If you want to create a new private queue, then you need to add the special string Private$ when supplying the path to the queue. For example, the page in Listing 26.9 creates a new private queue named PrivateOrders .

Listing 26.9 CreatePrivateQueue.aspx
 <%@ Import Namespace="System.Messaging" %> <Script runat="Server"> Sub Page_Load   If Not MessageQueue.Exists( ".\Private$\PrivateOrders" ) Then     MessageQueue.Create( ".\Private$\PrivateOrders" )   End If End Sub </Script> <html> <head><title>CreatePrivateQueue.aspx</title></head> <body> <h2>PrivateOrders Created!</h2> </body> </html> 

The C# version of this code can be found on the CD-ROM.

Sending Messages to a Queue

You can use the Send() method of the MessageQueue class to add a new message to a queue. You can use the Send() method regardless of whether you are sending a message that consists of a simple string or you are sending a message that contains an instance of a custom Visual Basic class.

The page in Listing 26.10 sends messages to a queue named myQueue .

Listing 26.10 SendQueue.aspx
 <%@ Import Namespace="System.Messaging" %> <Script runat="Server"> Sub Button_Click( s As Object, e As EventArgs )   Dim mqMessages As MessageQueue   If Not MessageQueue.Exists( ".\myQueue" ) Then     MessageQueue.Create( ".\myQueue" )   End If   mqMessages = New MessageQueue( ".\myQueue" )   mqMessages.Send( txtMessageBody.Text, txtMessageLabel.Text )   txtMessageLabel.Text = ""   txtMessageBody.Text = "" End Sub </Script> <html> <head><title>SendQueue.aspx</title></head> <body> <h2>Send Message to Message Queue</h2> <form runat="Server"> <b>Message Label</b> <br> <asp:TextBox   id="txtMessageLabel"   Runat="Server" /> <p> <b>Message Body</b> <br> <asp:TextBox   ID="txtMessageBody"   TextMode="Multiline"   Columns="50"   Rows="10"   Runat="Server" /> <br> <asp:Button   Text="Send Message!"   OnClick="Button_Click"   Runat="Server" /> </form> </body> </html> 

The C# version of this code can be found on the CD-ROM.

The page in Listing 26.10 contains a form with two TextBox controls (see Figure 26.4). The first text box is for a message label and the second text box is for a message body. When you submit the form, the Button_Click subroutine is executed.

Figure 26.4. Sending a message to the queue.

graphics/26fig04.jpg

The Button_Click subroutine creates an instance of the MessageQueue class. The Send() method is called to add a new message to the myQueue message. The new message is created with the label from the txtMessageLabel control and the body from the txtMessageBody control.

If you need more fine-grained control over the properties of a message that you send to a queue, then you should explicitly create an instance of the Message class. For example, you can use the properties of the Message class to specify a message's priority, whether an acknowledgement should be returned for a message, and a message timeout.

The page in Listing 26.11 sends three messages with three different priorities.

Listing 26.11 MessagePriorities.aspx
 <%@ Import Namespace="System.Messaging" %> <Script runat="Server"> Sub Page_Load   Dim mqMessages As MessageQueue   Dim mqMessage As Message   If Not MessageQueue.Exists( ".\myQueue" ) Then     MessageQueue.Create( ".\myQueue" )   End If   mqMessages = New MessageQueue( ".\myQueue" )   ' Send Message 1   mqMessage = New Message()   mqMessage.Label = "Message 1"   mqMessage.Body = "This is message 1"   mqMessage.Priority = MessagePriority.Normal   mqMessages.Send( mqMessage )   ' Send Message 2   mqMessage = New Message()   mqMessage.Label = "Message 2"   mqMessage.Body = "This is message 2"   mqMessage.Priority = MessagePriority.Lowest   mqMessages.Send( mqMessage )   ' Send Message 3   mqMessage = New Message()   mqMessage.Label = "Message 3"   mqMessage.Body = "This is message 3"   mqMessage.Priority = MessagePriority.Highest   mqMessages.Send( mqMessage ) End Sub </Script> <html> <head><title>MessagePriorities.aspx</title></head> <body> <h2>Messages Sent!</h2> </body> </html> 

The C# version of this code can be found on the CD-ROM.

Each of the three messages sent in Listing 26.11 is sent with a different message priority. The third message will be delivered first (because it has the highest priority), followed by the first and second.

Retrieving Messages from a Queue

The classes in the System.Messaging namespace include a number of different methods for retrieving messages from a queue. Some of these methods are synchronous and some are asynchronous. Some of these methods automatically remove a message from a queue, other methods enable you to peek at a message without removing it.

One of the most flexible methods of retrieving messages from a queue is the GetMessageEnumerator() method. This method returns an enumerator that enables you to iterate through all the messages in the queue in order of priority.

For example, the page in Listing 26.12 displays the labels of all the current messages in the myQueue queue.

Listing 26.12 GetmessageEnumerator.aspx
 <%@ Import Namespace="System.Messaging" %> <Script runat="Server"> Sub Page_Load   Dim enumMessages As MessageEnumerator   Dim mqMessages As MessageQueue   Dim mqMessage As Message   mqMessages = New MessageQueue( ".\myQueue" )   enumMessages = mqMessages.GetMessageEnumerator()   While enumMessages.MoveNext     mqMessage = CType( enumMessages.Current, Message )     lblMessages.Text &= "<li>" & mqMessage.Label   End While End Sub </Script> <html> <head><title>GetMessageEnumerator.aspx</title></head> <body> <asp:Label   id="lblMessages"   Runat="Server" /> </body> </html> 

The C# version of this code can be found on the CD-ROM.

You can also use the enumerator returned by the GetMessageEnumerator() to remove messages from a queue. The page in Listing 26.13 retrieves a single message at a time from the queue. After the message is retrieved and displayed, it's deleted from the queue with the RemoveCurrent() method.

Listing 26.13 RemoveCurrent.aspx
 <%@ Import Namespace="System.Messaging" %> <Script runat="Server"> Sub Page_Load   Dim enumMessages As MessageEnumerator   Dim mqMessages As MessageQueue   Dim mqMessage As Message   mqMessages = New MessageQueue( ".\myQueue" )   enumMessages = mqMessages.GetMessageEnumerator()   If enumMessages.MoveNext Then     mqMessage = CType( enumMessages.Current, Message )     mqMessage.Formatter = New XmlMessageFormatter( New String(){ "System.String" } )     lblMessageLabel.Text = mqMessage.Label     lblMessageBody.Text = mqMessage.Body     enumMessages.RemoveCurrent()   End If End Sub </Script> <html> <head><title>RemoveCurrent.aspx</title></head> <body> <form runat="Server"> <b>Message Label</b> <br> <asp:Label   id="lblMessageLabel"   EnableViewState="False"   Runat="Server" /> <p> <b>Message Body</b> <br> <asp:Label   id="lblMessageBody"   EnableViewState="False"   Runat="Server" /> <p> <asp:Button   Text="Next Message"   Runat="Server" /> </form> </body> </html> 

The C# version of this code can be found on the CD-ROM.

Displaying the Body of a Message

When you create a new message, the body of the message is automatically serialized before the message is added to a queue. By default, the message is serialized using the XmlMessageFormatter . Serialization when you send a message is automatic. You just send the message and all the serialization happens in the background.

NOTE

To learn more about serialization, see Chapter 25, "Working with the File System."


When you receive a message, however, you have to do some work to deserialize the message. You have to tell the XmlMessageFormatter about the types of objects that it should expect to receive.

For example, the page in Listing 26.14 adds two types of messages to a queue. The first type is a string and the second type is a number (a number of type double).

Listing 26.14 TargetTypes.aspx
[View full width]
 <%@ Import Namespace="System.Messaging" %> <Script runat="Server"> Sub Page_Load   Dim mqMessages As MessageQueue   Dim enumMessages As MessageEnumerator   Dim mqMessage As Message   If Not MessageQueue.Exists( ".\myQueue" ) Then     MessageQueue.Create( ".\myQueue" )   End If   mqMessages = New MessageQueue( ".\myQueue" )   ' Send String Message   mqMessages.Send( "This is a string", "Message 1" )   ' Send Decimal Message   mqMessages.Send( 12.34, "Message 2" )   ' Read from Queue   enumMessages = mqMessages.GetMessageEnumerator()   While enumMessages.MoveNext     mqMessage = CType( enumMessages.Current, Message )     mqMessage.Formatter = New XmlMessageFormatter( New String(){ "System.String", "System graphics/ccc.gif .Double" } )     lblMessages.Text &= "<li>" & mqMessage.Label     lblMessages.Text &= "<br>" & mqMessage.Body   End While End Sub </Script> <html> <head><title>TargetTypes.aspx</title></head> <body> <asp:Label   id="lblMessages"   Runat="Server" /> </body> </html> 

The C# version of this code can be found on the CD-ROM.

When each message is returned from the MessageEnumerator in Listing 26.14, an instance of the XmlMessageFormatter object is assigned to the Message object's Formatter property. The XmlMessageFormatter is initialized with the possible types of objects that might need to be deserialized. In this case, the body of the message might contain either a System.String or System.Double .

If the body of a message contains an unexpected type, you'll receive the error illustrated in Figure 26.5.

Figure 26.5. Unrecognized target type.

graphics/26fig05.jpg

Sending and Receiving Complex Messages

You can send and retrieve custom objects from a message queue. The only requirement is that the total size of the object not exceed four megabytes.

For example, if you plan to send product orders from a Web site to a central orders database, then it would make sense to create a custom ProductOrder class. Listing 26.15 contains the source code for this class.

Listing 26.15 ProductOrder.vb
 Imports System Namespace myComponents Public Class ProductOrder   Public ProductName As String   Public UnitPrice As Decimal   Public Quantity As Integer   Public EntryDate As DateTime End Class End Namespace 

The C# version of this code can be found on the CD-ROM.

Before you can use the ProductOrder class, you'll need to compile it by executing the following statement from a command prompt:

 
 vbc /t:library ProductOrder.vb 

Next, you'll need to copy the compiled assembly ( ProductOrder.dll ) to your application /bin directory so that it is visible to the ASP.NET pages in your application.

After you create the ProductOrder class, you can use it when sending messages to a queue. The page in Listing 26.16 contains a form that enables you to add new product orders to a queue named ProductOrders .

Listing 26.16 SendProductOrder.aspx
 <%@ Import Namespace="myComponents" %> <%@ Import Namespace="System.Messaging" %> <Script runat="Server"> Sub Button_Click( s As Object, e As EventArgs )   Dim mqMessages As MessageQueue   Dim objProduct As ProductOrder   ' Create Product Order   objProduct = New ProductOrder()   objProduct.ProductName = txtProductName.Text   objProduct.UnitPrice = txtUnitPrice.Text   objProduct.Quantity = txtQuantity.Text   objProduct.EntryDate = DateTime.Now()   ' Check for ProductOrders Queue   If Not MessageQueue.Exists( ".\ProductOrders" ) Then     MessageQueue.Create( ".\ProductOrders" )   End If   ' Send Product Order   mqMessages = New MessageQueue( ".\ProductOrders" )   mqMessages.Send( objProduct, "Product Order" )   ' Clear Form Fields   txtProductName.Text = ""   txtUnitPrice.Text = ""   txtQuantity.Text = "" End Sub </Script> <html> <head><title>SendProductOrder.aspx</title></head> <body> <h2>Place Product Order</h2> <form runat="Server"> <b>Product Name</b> <br> <asp:TextBox   id="txtProductName"   Runat="Server" /> <p> <b>Unit Price</b> <br> <asp:TextBox   ID="txtUnitPrice"   Runat="Server" /> <p> <b>Quantity</b> <br> <asp:TextBox   ID="txtQuantity"   Runat="Server" /> <p> <asp:Button   Text="Place Order!"   OnClick="Button_Click"   Runat="Server" /> </form> </body> </html> 

The C# version of this code can be found on the CD-ROM.

When you submit a product order with the form in Listing 26.16, an instance of the ProductOrder class is created. Next, the ProductOrder is sent to the ProductOrders queue with the Send() method.

The page in Listing 26.17 illustrates how you can retrieve product orders from the ProductOrders queue.

Listing 26.17 EnumerateProducts.aspx
[View full width]
 <%@ Import Namespace="myComponents" %> <%@ Import Namespace="System.Messaging" %> <Script runat="Server"> Sub Page_Load   Dim enumMessages As MessageEnumerator   Dim mqMessages As MessageQueue   Dim mqMessage As Message   Dim objProduct As ProductOrder   mqMessages = New MessageQueue( ".\ProductOrders" )   enumMessages = mqMessages.GetMessageEnumerator()   If enumMessages.MoveNext Then     mqMessage = CType( enumMessages.Current, Message )     mqMessage.Formatter = New XmlMessageFormatter( New String(){ "myComponents graphics/ccc.gif .ProductOrder,ProductOrder" } )     objProduct = New ProductOrder     objProduct = mqMessage.Body     lblProductName.Text = objProduct.ProductName     lblUnitPrice.Text = objProduct.UnitPrice     lblQuantity.Text = objProduct.Quantity     lblEntryDate.Text = objProduct.EntryDate     enumMessages.RemoveCurrent()   End If End Sub </Script> <html> <head><title>EnumerateProducts.aspx</title></head> <body> <form runat="Server"> <b>Product Name:</b> <br> <asp:Label   id="lblProductName"   EnableViewState="False"   Runat="Server" /> <p> <b>Unit Price</b> <br> <asp:Label   id="lblUnitPrice"   EnableViewState="False"   Runat="Server" /> <p> <b>Quantity</b> <br> <asp:Label   id="lblQuantity"   EnableViewState="False"   Runat="Server" /> <p> <b>Entry Date</b> <br> <asp:Label   id="lblEntryDate"   EnableViewState="False"   Runat="Server" /> <p> <asp:Button   Text="Next Order"   Runat="Server" /> </form> </body> </html> 

The C# version of this code can be found on the CD-ROM

Notice that the full name of the ProductOrder class, myComponents.ProductOrder, ProductOrder , is used when initializing the XmlMessageFormatter to deserialize the message body. This page simply grabs the first product order off the queue, displays the order, and deletes it from the queue.



ASP.NET Unleashed
ASP.NET 4 Unleashed
ISBN: 0672331128
EAN: 2147483647
Year: 2003
Pages: 263

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