Service Bus for Windows Server: A Primer, Part II

In my last post on Service Bus for Windows, we covered the overview, installation and configuration of SBWS. Now it’s time to dive into the API and see it in action. The code snippets in this post will focus on Service Bus queues. Beyond queues, Service Bus also supports topics and subscriptions mode to allow independent retrieval with filtered view of the published message stream.

Project References

To set up the development environment, right-click References in Solution Explorer, then click Add Library Package Reference. Search with the “ServiceBus.v” keyword, as there are many service bus related Nuget packages. As of this writing, the latest version is 1.1. Please make sure to download the version consistent with your Service Bus installation.

System.Runtime.Serialization dll is also needed for the code snippets below.

Queue Operations

In the following code snippets, we are going to show detailed steps on how a queue is created, and how messages are sent to and retrieved from the queue.

1. Get the user credential.

 // Populate NetworkCredential
 NetworkCredential credential = new NetworkCredential("lei.zhong", "mypassword", "appliedis.com");

2. Create service bus and security token service end points.

var sbUriList = new List<Uri>() { new UriBuilder { Scheme = "sb", Host = " mylaptop.appliedis.com", Path = "ServiceBusDefaultNamespace" }.Uri };

var httpsUriList = new List<Uri>() { new UriBuilder { Scheme = "https", Host = "mylaptop.appliedis.com", Path = "ServiceBusDefaultNamespace", Port = 9355 }.Uri };

3. Create MessagingFactory. The factory will be used later to create queue client to send/receive messages. Note two types of end points are used for token provider and MessagingFactory respectively.

TokenProvider tokenProvider = TokenProvider.CreateOAuthTokenProvider(httpsUriList, credential);

    MessagingFactory messagingFactory = MessagingFactory.Create(sbUriList, tokenProvider);

4. Create a queue. This involves a few steps.

First, create ServiceBusConnectionStringBuilder.

ServiceBusConnectionStringBuilder connBuilder = new ServiceBusConnectionStringBuilder { ManagementPort = 9355, RuntimePort = 9354 };
            connBuilder.Endpoints.Add(sbUriList[0]);
            connBuilder.StsEndpoints.Add(httpsUriList[0]);

Next, create a NamespaceManager.

NamespaceManager namespaceManager = NamespaceManager.CreateFromConnectionString(connBuilder.ToString());
namespaceManager.Settings.TokenProvider = tokenProvider;

 const string newQueueName = "MyQueue";

	// check if queue exists
	if (namespaceManager.QueueExists(newQueueName)) return; 

Finally, let’s create the queue. Queue parameters are wrapped in QueueDescription class.

var queueDescription = new QueueDescription(newQueueName);
 queueDescription.LockDuration = new TimeSpan(0, 1, 0); // 1 minute
 queueDescription.MaxDeliveryCount = 3;

namespaceManager.CreateQueue(queueDescription);

Note: the lockDuration is the duration of a peek lock on a message – the amount of time that the message is locked for other receivers. The maximum value for LockDuration is five minutes. MaxDelivery is the maximum delivery count after which a message is automatically deadlettered. We’ll revisit the dead letter issue later.

5. Let’s send a message to Queue. The class BrokerMessage can wrap any object type but for demo purpose let’s just send a string. I strongly recommend storing same types of objects in a given queue to make queue retrieval easier, which makes sense from business perspective anyway.

Since we already have the MessageFactory configured, creating a queue client off it is just one line of code. You can ignore the dead letter client for now, but it is also straightforward.

QueueClient queueClient = messagingFactory.CreateQueueClient(newQueueName, ReceiveMode.PeekLock);
        QueueClient deadLetterQueueClient = messagingFactory.CreateQueueClient(QueueClient.FormatDeadLetterPath(queueClient.Path), ReceiveMode.ReceiveAndDelete);

        queueClient.Send(new BrokeredMessage(&"Hello, service bus!"));

Here, ReceiveMode.PeekLock is to keep the message peek-locked until the receiver abandons the message, while ReceiveAndDelete is to delete the message after it is received. The first mode allows a message to be peeked (and thus processed) multiple times. I use this mode in scenario where the processing of message may fail and it needs to be returned to the queue for another retrieval.

6. Now, let’s receive the message. The BrokerMessage will be dehydrated to the correct object type (string in our case).

BrokeredMessage message = queueClient.Receive();
string messageBody = message.GetBody<string>();
Console.WriteLine(messageBody);
Console.Read();

As you might have expected, there is a batch receive method ReceiveBatch which returns IEnumerable<BrokeredMessage>. It has three overloaded flavors documented here.

At this point, the message can be marked completed by calling message.Compete(), or be returned to the queue by calling message.Abandon(), depending if the message has to be consumed/processed again based on your business logic.

Here’s a more complete code block:

// Populate NetworkCredential
NetworkCredential credential = new NetworkCredential("lei.zhong", " mypassword", "appliedis.com");

var sbUriList = new List<Uri>() { new UriBuilder { Scheme = "sb", Host = "mylaptop.appliedis.com", Path = "ServiceBusDefaultNamespace" }.Uri };
var httpsUriList = new List<Uri>() { new UriBuilder { Scheme = "https", Host = " mylaptop.appliedis.com", Path = "ServiceBusDefaultNamespace", Port = 9355 }.Uri };

TokenProvider tokenProvider = TokenProvider.CreateOAuthTokenProvider(httpsUriList, credential);
MessagingFactory messagingFactory = MessagingFactory.Create(sbUriList, tokenProvider);

ServiceBusConnectionStringBuilder connBuilder = new ServiceBusConnectionStringBuilder { ManagementPort = 9355, RuntimePort = 9354 };
connBuilder.Endpoints.Add(sbUriList[0]);
connBuilder.StsEndpoints.Add(httpsUriList[0]);

NamespaceManager namespaceManager = NamespaceManager.CreateFromConnectionString(connBuilder.ToString());
namespaceManager.Settings.TokenProvider = tokenProvider;

// Create queue
const string newQueueName = "MyQueue";
if (!namespaceManager.QueueExists(newQueueName))
{
var queueDescription = new QueueDescription(newQueueName);

queueDescription.LockDuration = new TimeSpan(0, 1, 0);
queueDescription.MaxDeliveryCount = 3;
namespaceManager.CreateQueue(queueDescription);
}

// Send message to queue
QueueClient queueClient = messagingFactory.CreateQueueClient(newQueueName, ReceiveMode.PeekLock);
QueueClient deadLetterQueueClient = messagingFactory.CreateQueueClient(QueueClient.FormatDeadLetterPath(queueClient.Path), ReceiveMode.ReceiveAndDelete);

queueClient.Send(new BrokeredMessage("Hello, service bus!"));

BrokeredMessage message = queueClient.Receive();

string messageBody = message.GetBody<string>();
Console.WriteLine(messageBody);

Console.Read();

Dead Letter

The dead letter queue can be considered an internal, shadow queue of a normal queue. It is automatically created when a queue is created. Dead letter queue is where a message ends up eventually if its delivery count exceeds the specified maximum delivery count.

When creating a queue, we can specify the maximum delivery count. This value is immutable once a queue is created.

queueDescription.MaxDeliveryCount = 3;

You may explicitly put a message into the dead letter queue:

message.DeadLetter();

The dead letter queue client is created like this:

deadLetterQueueClient = messagingFactory.CreateQueueClient(QueueClient.FormatDeadLetterPath(queueClient.Path), ReceiveMode.ReceiveAndDelete);

Note here that ReceiveMode.ReceiveAndDelete is used simply because I only want to take one shot processing the message.

Service Bus Explorer

In my first post on SBWS I mentioned Service Bus Explorer as a helpful administrative tool. The source code can be found here. The code is well laid out but the UI leaves a lot to be desired (for instance, if a client wanted to refresh all queues in one single key stroke). Feel free to tweak it to meet your needs.

Note: If you are using SBWS 1.0, use the source code version 1.8 included the download.

One desired function I wanted was to view the content of the message upon peek or receive from the popup menu.

The location of the code is GetMessageAndProperties method in ServiceBusHelper.cs. Basically, you will use the correct generic type in this:

T content = message.GetBody();

Once you get ahold of strong typed content, the detailed information of the object can be viewed.

Summary

In this post we have covered basic operations of Service Bus queue to get you started. In the third (and final) post of the series, we’ll discuss some real world technical issues. Stay tuned.

About Lei Zhong

Lei Zhong is a software engineer with over 12 years of non-stop development experience in Microsoft technologies. He has worked for top-notch consulting firms, start-ups and commercial software firms with clients from various industries. He enjoys working in both front end and middle tier, and never hesitates to dive into database for optimal performance. He always strives to deliver well-structured code that not only works in current release but is easy and flexible enough for maintenance and future enhancement needs. He is MCPD in Web development, MCTS in SharePoint configuration/development, Distributed application, and SQL Server.