0 Comments Posted in:

In this series:

In our last post, we saw how to create an Azure Service Bus namespace, get its connection string, and create a queue using the Azure CLI. In this post, we're going to send our first message to a queue, and see how to receive it, in a .NET Core application, using the Azure Service Bus SDK.

Step 1 - Creating a project

For this simple demo, we're going to create two .NET Core console applications - one that can send messages, and one that can receive messages. We'll make two separate applications to demonstrate that the sender and receiver are often completely different applications, and also that they don't need to be running at the same time. Assuming you have the .NET Core SDK installed, you can use dotnet new to create the console app, and the convenient dotnet add package command to reference the Microsoft.Azure.ServiceBus NuGet package which contains the Azure Service Bus SDK.

Here's what I typed in PowerShell to create the "sender project"

md sender
cd sender
dotnet new console
dotnet add package Microsoft.Azure.ServiceBus

Step 2 - Sending a message

I've kept the "Sender" project as simple as possible. I pass the connection string (which we saw how to get in the previous installment) as a command line parameter. Then we create a QueueClient for the queue that we want to send the message to. If you remember we already created a queue called queue1.

The message body is essentially the payload that we want to send. This is simply a byte array, so you can use any form of serialization you like. It's very common to serialize as JSON, and it's also possible to compress or encrypt the contents of a message. We'll perhaps look at those topics later in this series, but for now I'm just taking the message text (which is the second parameter to our console app), converting it into a byte array and using that as the message body. The most important thing about the message body is to ensure that it is in a format that receivers can easily interpret.

We then construct a Message object. This has some interesting additional properties we will explore later but for now we don't need any of them, and we'll send the message with SendAsync on the QueueClient.

static async Task Main(string[] args)
{
    var connectionString = args[0];
    var queueName = "queue1";
    var queueClient = new QueueClient(connectionString, queueName);
    var messageText = args[1];
    var body = Encoding.UTF8.GetBytes(messageText);
    var message = new Message(body);
    await queueClient.SendAsync(message);
    Console.WriteLine("Sent message");
}

We can run this with dotnet run $connectionString "hello world", and this will post a message containing "hello world" to queue1. Note that the receiving application doesn't need to be running. Azure Service Bus will hold onto this message until the receiver runs.

Step 3 - Receiving Messages

I've created a separate console application called Receiver for the purposes of receiving messages. Azure Service Bus does allow you to connect to a single queue and just ask for one message at a time, but the SDK encourages you to use a technique where you simply register a "message handler". That message handler will be called every time a message is received. The SDK behind the scenes uses an industry standard protocol called AMQP to receive those messages from Service Bus.

Let's look at the code for the Main method in our Receiver application, which was created in exactly the same way as we saw for the Sender application above. Notice again that we create a QueueClient using the Service Bus connection string that we pass in as a command line parameter. Then we use RegisterMessageHandler to tell it which method to call when we receive a message - in our case OnMessage. And there are also some custom options we can provide (we'll look in more detail at those later in this series), which requires us to also provide an exception handler - ours is called OnException. Then we just need to block which we're doing by waiting for a keypress, as the message pump runs in the background. In a real-world application that is processing queue messages, you'd probably want to consider using the .NET Core "worker service" template which is ideal for this kind of use case.

static void Main(string[] args)
{
    var connectionString = args[0];
    var queueName = "queue1";
    var queueClient = new QueueClient(connectionString, queueName);
    var messageHandlerOptions = new MessageHandlerOptions(OnException);
    queueClient.RegisterMessageHandler(OnMessage, messageHandlerOptions);
    Console.WriteLine("Listening, press any key");
    Console.ReadKey();
}

Let's look at the OnMessage message handler. We get passed a Message object, which allows us to access its Body property, which in our case just contains a string in UTF8 encoding, so reading that string out is easy. Notice that I'm also accessing one of the SystemProperties of a message - in this case we can see the EnqueuedTimeUtc which tells us when this particular message was sent.

static Task OnMessage(Message m, CancellationToken ct)
{
    var messageText = Encoding.UTF8.GetString(m.Body);
    Console.WriteLine("Got a message:");
    Console.WriteLine(messageText);
    Console.WriteLine($"Enqueued at {m.SystemProperties.EnqueuedTimeUtc}");
    return Task.CompletedTask;
}

The final bit of code I've not shown is the OnException method. This allows us to gracefully handle any issues receiving messages. I'm just outputting information to the console in this example for now.

static Task OnException(ExceptionReceivedEventArgs args)
{
    Console.WriteLine("Got an exception:");
    Console.WriteLine(args.Exception.Message);
    Console.WriteLine(args.ExceptionReceivedContext.ToString());
    return Task.CompletedTask;
}

When I run this on my machine, after having sent two messages in advance with my Sender application, I see the following output:

$> dotnet run $connectionString
Listening, press any key
Got a message:
message 1
Enqueued at 24/04/2020 08:48:47
Got a message:
message 2
Enqueued at 24/04/2020 08:48:52

We've seen in this post how the Azure Service Bus SDK makes it very straightforward to send and receive messages. In the next post we'll dive a bit deeper into some of the options we can configure when sending and receiving messages.

The code for these demos can be found in this GitHub repository

Vote on HN