The previous post described how to design a highly scalable solution using queue oriented architecture.
This post will cover the fundamentals to get started with Microsoft Message Queuing (MSMQ). Code examples are provided to illustrate how to create a queue, write messages to a queue and read messages from a queue synchronously and asynchronously.
Download Source Code
Setup
The pre-requisite is to install MSMQ, which comes free with Windows.
Creating a queue
The following code was used for creating the queue named orders.
using System.Messaging;
if (!MessageQueue.Exists(@".\Private$\Orders"))
{
MessageQueue.Create(@".\Private$\Orders");
}
Note: Creating queues on a server requires powerful permissions. You may want to consider creating queues via an installer as 1) installers typically run as highly privileged users and 2) application security can be improved by following the principle of least privilege.
The orders queue and messages on the queue can be viewed using Computer Management as shown below.
Writing Messages
The following code was used for writing the OrderModel DTO instance (message) to the queue using a BinaryMessageFormatter.
[Serializable]
public class OrderModel
{
public int Id { get; set; }
public string Name { get; set; }
}
using (var queue = new MessageQueue(@".\Private$\Orders"))
{
queue.Formatter = new BinaryMessageFormatter();
var order = new OrderModel()
{
Id = 123,
Name = "Demo Order"
};
queue.Send(order);
}
Reading Messages
Blocking Synchronous Read
The following code was used for reading a message from the queue. The thread will be blocked on the receive method on line 5 until a message is available.
using (var queue = new MessageQueue(@".\Private$\Orders"))
{
queue.Formatter = new BinaryMessageFormatter();
var message = queue.Receive();
var order = (OrderModel)message.Body;
}
A read timeout duration can be specified. The code below will use a 1 sec timeout limit and catch the MessageQueueException raised due to the timeout. A custom ReadTimeoutException is thrown to notify the client that a timeout has occured.
public class ReadTimeoutException : Exception
{
public ReadTimeoutException(string message, Exception innerException)
: base(message, innerException)
{
}
}
using (var queue = new MessageQueue(@".\Private$\Orders"))
{
queue.Formatter = new BinaryMessageFormatter();
Message message = null;
try
{
message = queue.Receive(TimeSpan.FromSeconds(1));
}
catch (MessageQueueException mqException)
{
if (mqException.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout)
{
throw new ReadTimeoutException("Reading from the queue timed out.",
mqException);
}
throw;
}
}
Note: Throwing a custom exception such as ReadTimeoutException is considered good practice because we can swap the queueing implementation with different technology such as Azure Service Bus without modifying the client code.
Asynchronous Read
The following code was used to perform an async read in conjunction with a Task.
private async Task<OrderModel> ReadAsync()
{
using (var queue = new MessageQueue(@".\Private$\Orders"))
{
queue.Formatter = new BinaryMessageFormatter();
var message = await Task.Factory.FromAsync<Message>(
queue.BeginReceive(), queue.EndReceive);
return (OrderModel)message.Body;
}
}
Summary
This post covered the fundamentals of using a MSMQ to read and write messages.
The next post describes various message delivery strategies.