Practical .NET

Offloading Work from Your Application with a Queue

Sometimes you can improve your application's response time by shunting some activities to offline processing -- sending an e-mail response, for instance. Here's how to use Microsoft Message Queue (available on both your development and production computers) to simplify the process.

You can always improve your application's response time by doing less. One way of doing less is to move tasks offline for processing later. "Later" in this case might mean "this evening" or even "five seconds later on another computer." The easiest way to do that is to have your application write the necessary information to a Microsoft Message Queue (MSMQ) and have another application read it and process the information. The queue can even be transactional; should you roll back the transaction, your MSMQ entries will also be backed out. In this column, I'm going to look at writing to the queue, along with how to create a queue from code to simplify deployment.

Adding MSMQ and Creating a Queue
MSMQ is an optional component for Windows. If MSMQ isn't installed, it's easy to add. In Windows Server 2008, start Server Manager, select Action | Add Feature. In the resulting dialog, check Message Queuing; In Windows 7, open Control Panel | Programs and Features, then select Turn Windows Features on or off. Once there, drill down before checking off MSMQ.

You can manage queues from within Visual Studio: Open Server Explorer, drill down through Servers and the name of your computer to get to Message Queues. To add a queue, right-click Private Queues and select Create Queue. To create a queue, you just need to supply a name. Optionally, you can check the Make queue transactional option to include your queue messages in transactions.

There is one problem with adding queues this way: You'll need to recreate the queue on your production computer when it comes time to deploy to production. A better strategy is to have your code check to see if the queue exists on the computer, and create the queue if necessary. Before working with queues, you'll need to add a reference to System.Messaging.

This code checks to see if a queue called "emails" exists in Private Queues, and if the queue doesn't exist, creates it. By passing True as the second parameter, this code makes the queue transactional:

If Not MessageQueue.Exists(".\private$\emails") Then
  MessageQueue.Create(".\private$\Emails", True)
End If

In this code, the dot represents the local computer. Security permitting, you can replace that dot with the name of another computer on your network and read or write messages to that computer.

Once the queue's created, you can retrieve a reference to the queue by creating a MessageQueue object, passing the name of the queue:

Dim q As New MessageQueue(".\private$\emails")

Reading and Writing Messages
The next step is to create an MSMQ message and put your message into its Body property. You'll probably want to do more than that, though.

By default, MSMQ doesn't save any messages to your hard disk. Instead, to improve performance, messages are held in memory. However, that means should the computer crash, your messages will be lost. To prevent that, you should set the Recoverable property on the Message to True to ensure that the message is saved to disk. To make your life easier, you should also set the Label property on the Message because that property is displayed when viewing messages in Server Explorer -- you'll need that Label to find messages (and for that same reason, it should be a unique identifier).

Putting that all together, a bare-bones message might look like the following code:

Dim msg As New Message()
msg.Body = "Data"
msg.Recoverable = True
emm.Label = "New Message " & DateTime.Now.ToShortTimeString
q.Send(msg, MessageQueueTransactionType.Single)

Note that the second parameter passed to the Send method is required with a transactional queue.

Other properties let you encrypt the message and set related queues. For instance, you can also specify the dead-letter queue in which to put the message if it can't be delivered, or specify a queue to which an acknowledgement is to be sent when the object is read.

That code works fine as long as your Message Body property just holds text. A more typical solution requires writing multiple pieces of information. For instance, assuming that I want to send e-mail confirmation messages offline, I'd create a class to hold that information:

Public Class EmailMessage
  Public Property ToAddress As String
  Public Property Subject As String
  Public Property Body As String
End Class

Before putting an object into the Body property, you must format it. You can do that in a number of ways; but because all I want to pass is the data in my object, I use the XMLMessageFormatter class. To create an XMLFormatter object, you need to pass it an array of Type objects created from the class (or classes) that you're formatting. Once you've created the formatter, you must put it in the Message's Formatter property. The code to create and initialize my EmailMessage object before putting it in a Message:

Dim emm As New EmailMessage
emm.ToAddress = "[email protected]"
emm.Subject = "Your email confirmation"
emm.Body = "Your purchase has been approved."
       
Dim msgType(0) As Type
msgType(0) = GetType(EmailMessage)
Dim msg As New Message()
msg.Formatter = New XmlMessageFormatter(msgType)
msg.Body = emm

Now that you have a message on the queue, you'll want to read it. I'll look at that in my next column, along with where you should put that code.

About the Author

Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.

comments powered by Disqus

Featured

  • AI for GitHub Collaboration? Maybe Not So Much

    No doubt GitHub Copilot has been a boon for developers, but AI might not be the best tool for collaboration, according to developers weighing in on a recent social media post from the GitHub team.

  • Visual Studio 2022 Getting VS Code 'Command Palette' Equivalent

    As any Visual Studio Code user knows, the editor's command palette is a powerful tool for getting things done quickly, without having to navigate through menus and dialogs. Now, we learn how an equivalent is coming for Microsoft's flagship Visual Studio IDE, invoked by the same familiar Ctrl+Shift+P keyboard shortcut.

  • .NET 9 Preview 3: 'I've Been Waiting 9 Years for This API!'

    Microsoft's third preview of .NET 9 sees a lot of minor tweaks and fixes with no earth-shaking new functionality, but little things can be important to individual developers.

  • Data Anomaly Detection Using a Neural Autoencoder with C#

    Dr. James McCaffrey of Microsoft Research tackles the process of examining a set of source data to find data items that are different in some way from the majority of the source items.

  • What's New for Python, Java in Visual Studio Code

    Microsoft announced March 2024 updates to its Python and Java extensions for Visual Studio Code, the open source-based, cross-platform code editor that has repeatedly been named the No. 1 tool in major development surveys.

Subscribe on YouTube