Azure Service Bus Topics in .Net Framework 4
I’ve done queue processing wrong a few times in my career. I can admit to that. I’ve made a lot of use of Azure Storage Queues because they’re extremely cheap (you pay for the storage only, which is about 7p/GB/month at globe-scale) and very easy to integrate.
Thing is, sometimes a queue doesn’t actually do everything you think it does. If you make a simple queue and expect two different services to both process messages from it, you’re going to have a bad time. That’s because you’re actually looking for a Topic, and the pub-sub model.
Hey, I started writing this a few weeks ago and dropped it. I’ve picked up the bits that matter and cut the post a little short just to get it out, so it’s a little specific. If you got here by Google, perhaps it’s just what you’re looking for! :)
Creating a Service Bus
Easy enough in the Azure portal. Navigate to the ‘Service Bus’ resource type, and go through the create process.
Things to note:
- You can only use Topics at Standard and Premium tiers
- Basic tier is essentially the same as a Storage Queue. Standard adds Topics and an SLA for ~£10/mo, Premium costs A LOT at £668/mo.
Nuget packages for integrating Service Bus
The pertinent Nuget packages for Service Bus are:
- The ‘next generation’ one: Microsoft.Azure.ServiceBus (source code)
- The older one that’s still maintained: WindowsAzure.ServiceBus
The docs examples are good at using the new Nuget package. Here’s a nice entry point to the new docs for getting started with service bus queues.
You might need to dig through the package archives if you are using an old .Net framework version:
.Net version | Newest package version |
---|---|
Core 2+ | Latest* |
Fx 4.6.2 | Latest* |
Fx 4.6.1 | https://www.nuget.org/packages/Microsoft.Azure.ServiceBus/3.4.0 |
Fx 4.6 | https://www.nuget.org/packages/WindowsAzure.ServiceBus/5.0.0 |
Fx 4.5.2 | https://www.nuget.org/packages/WindowsAzure.ServiceBus/4.1.11 |
Fx 4.5 | https://www.nuget.org/packages/WindowsAzure.ServiceBus/4.1.3 |
*Note that as the newest package versions target .Net Standard 2.0, that equals support for .Net Core 2+ as well as .Net Fx 4.6.1+, but if you don’t want to pull down the universe of .Net Core compatibility libraries, the last version to explicitly target .Net Fx 4.6.1 is listed above. See the MS .Net Standard page for info.
Hierarchy of service bus concepts
- The base resource is a ‘Service Bus Namespace’ (which we commonly just call the Service Bus)
- Within the namespace, you can create one or more entities
- Each entity is a queue or a topic
- A topic contains one or more subscriptions
Subscriptions are what makes it possible for more than one consumer to process a topic message. Messages are published to the topic, but they are consumed from the subscriptions, each of which has a copy of the message.
Get a connection string
To get a connection string, you need to go to your Service Bus in the Azure portal, go to Shared Access Signatures, and generate a signature with the privileges you need: Write, Listen, or Manage (manage is basically admin, and can both write and listen as well as create new topic subscriptions etc.)
Using Service Bus with a Topic in a .Net Framework 4.5 app
There’s a wealth of tutorials on the new library for .Net core. Let’s say I’m limited to using .Net 4.5.
I could make a solution with three projects; a sender console app, a receiver console app, and a common library containing the message class (to be shared by sender and receiver).
Sender
Every time the user presses Return, it will generate an instance of our shared PolicyMessage
class and send it to the topic:
using Microsoft.ServiceBus.Messaging;
static void Main(string[] args)
{
// Create a policy Application message
// and send it to the topic
var policyTopicSendConnectionString = "Endpoint=sb://sg-psl-apply.servicebus.windows.net/;SharedAccessKeyName=policytopicsend;SharedAccessKey=..........;EntityPath=policies";
var topicClient = TopicClient.CreateFromConnectionString(policyTopicSendConnectionString);
while(true)
{
var policyMessage = new PolicyMessage();
topicClient.Send(new BrokeredMessage(policyMessage));
Console.WriteLine("Sent: " + policyMessage.ToString());
Console.WriteLine("Press return to send another.");
Console.ReadLine();
}
}
Receiver
Sets up a delegate that fires any time a message comes in. We unwrap our PolicyMessage
from inside the BrokeredMessage
using .GetBody<T>
.
Setting AutoComplete
to false allows us to choose programatically when to mark a message as processed.
using Microsoft.ServiceBus.Messaging;
static void Main(string[] args)
{
// Read all Policy Application Messages
// and write them to screen
var policyTopicMasterConnectionString = "Endpoint=sb://sg-psl-apply.servicebus.windows.net/;SharedAccessKeyName=policytopicmaster;SharedAccessKey=..........";
Action<BrokeredMessage> onMessage = (bm) => {
var message = bm.GetBody<PolicyMessage>();
Console.WriteLine(message.ToString());
};
var subClient = SubscriptionClient.CreateFromConnectionString(policyTopicMasterConnectionString, "policies", "applications");
var options = new OnMessageOptions()
{
AutoComplete = false
};
subClient.OnMessage(onMessage, options);
Console.WriteLine("End of receiver program");
Console.ReadLine();
}
Some examples you’ll see elsewhere make use of MessagingFactory
but this didn’t work for me. I think it’s because it doesn’t give you the facility to pick a particular subscription, only a topic:
var messagingFactory = MessagingFactory.CreateFromConnectionString(policyTopicMasterConnectionString);
var receiver = messagingFactory.CreateMessageReceiver("policies");
receiver.OnMessage(onMessage, options);
Further reading
You can check out this piece about how Azure Storage Queues and Azure Service Bus Queues differ.
Build cool stuff, fix old stuff!