← Back to Tutorials
Beginner⏱️ 25 min

Send and Receive Messages with .NET SDK

Send and Receive Messages with .NET SDK

Architecture Overview

┌──────────────────┐                              ┌──────────────────┐
│  Sender Console  │                              │ Receiver Console │
│       App        │                              │       App        │
└────────┬─────────┘                              └────────┬─────────┘
         │                                                 │
         │  ServiceBusSender                ServiceBusReceiver
         │                                                 │
         ▼                                                 ▼
┌─────────────────────────────────────────────────────────────────────┐
│                    Azure Service Bus Namespace                       │
│  ┌───────────────────────────────────────────────────────────────┐  │
│  │                      orders-queue                              │  │
│  │  [Msg1] [Msg2] [Msg3] ──────────────────────────▶ [Consumer]  │  │
│  └───────────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────────┘

Prerequisites

RequirementDetails
.NET SDK8.0+
Service Bus NamespaceFrom previous tutorial
Queueorders-queue created
IDEVisual Studio / VS Code / Rider

Step 1 — Create a Console Application

dotnet new console -n ServiceBusDemo
cd ServiceBusDemo

Step 2 — Install the NuGet Package

dotnet add package Azure.Messaging.ServiceBus

Step 3 — Send a Single Message

using Azure.Messaging.ServiceBus;

const string connectionString = "<YOUR_CONNECTION_STRING>";
const string queueName = "orders-queue";

await using var client = new ServiceBusClient(connectionString);
ServiceBusSender sender = client.CreateSender(queueName);

var message = new ServiceBusMessage("Hello, Service Bus!");
await sender.SendMessageAsync(message);

Console.WriteLine("Message sent successfully.");

Screenshot: Console output after sending message

Step 4 — Send a Batch of Messages

using Azure.Messaging.ServiceBus;

const string connectionString = "<YOUR_CONNECTION_STRING>";
const string queueName = "orders-queue";

await using var client = new ServiceBusClient(connectionString);
ServiceBusSender sender = client.CreateSender(queueName);

using ServiceBusMessageBatch batch = await sender.CreateMessageBatchAsync();

for (int i = 1; i <= 10; i++)
{
    var message = new ServiceBusMessage($"Order #{i}");
    if (!batch.TryAddMessage(message))
    {
        throw new Exception($"Message {i} too large for batch.");
    }
}

await sender.SendMessagesAsync(batch);
Console.WriteLine($"Sent batch of {batch.Count} messages.");

Step 5 — Receive Messages

using Azure.Messaging.ServiceBus;

const string connectionString = "<YOUR_CONNECTION_STRING>";
const string queueName = "orders-queue";

await using var client = new ServiceBusClient(connectionString);
ServiceBusReceiver receiver = client.CreateReceiver(queueName);

Console.WriteLine("Receiving messages...");

IReadOnlyList<ServiceBusReceivedMessage> messages =
    await receiver.ReceiveMessagesAsync(maxMessages: 10, maxWaitTime: TimeSpan.FromSeconds(5));

foreach (ServiceBusReceivedMessage msg in messages)
{
    Console.WriteLine($"Received: {msg.Body}");
    await receiver.CompleteMessageAsync(msg);
}

Console.WriteLine($"Processed {messages.Count} messages.");

Screenshot: Console output receiving messages

Step 6 — Complete vs Abandon Messages

ActionMethodEffect
CompleteCompleteMessageAsync()Removes message from queue
AbandonAbandonMessageAsync()Returns message to queue, increments delivery count
DeferDeferMessageAsync()Moves to deferred state, receive by sequence number
Dead-letterDeadLetterMessageAsync()Moves to dead-letter sub-queue
foreach (ServiceBusReceivedMessage msg in messages)
{
    try
    {
        ProcessOrder(msg.Body.ToString());
        await receiver.CompleteMessageAsync(msg);
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Error: {ex.Message}. Abandoning message.");
        await receiver.AbandonMessageAsync(msg);
    }
}

Step 7 — Connection String vs Managed Identity

Connection String (development)

await using var client = new ServiceBusClient(connectionString);

Managed Identity (production recommended)

dotnet add package Azure.Identity
using Azure.Identity;
using Azure.Messaging.ServiceBus;

const string fullyQualifiedNamespace = "sb-demo-namespace.servicebus.windows.net";

await using var client = new ServiceBusClient(
    fullyQualifiedNamespace,
    new DefaultAzureCredential());
ApproachUse CaseSecurity
Connection StringLocal dev, quick testsShared secret — rotate regularly
Managed IdentityProduction, Azure-hosted appsNo secrets to manage
Workload IdentityKubernetes / AKSFederated token exchange

Assign RBAC Role for Managed Identity

az role assignment create \
  --assignee <PRINCIPAL_ID> \
  --role "Azure Service Bus Data Sender" \
  --scope /subscriptions/<SUB_ID>/resourceGroups/rg-servicebus-demo/providers/Microsoft.ServiceBus/namespaces/sb-demo-namespace

Screenshot: RBAC role assignment in portal

Summary

  • ✅ Created a .NET console app with the Service Bus SDK
  • ✅ Sent single and batch messages
  • ✅ Received and completed messages
  • ✅ Understood Complete vs Abandon semantics
  • ✅ Configured Managed Identity for production

Previous: Create a Service Bus Namespace and Queue

Next: Topics, Subscriptions, and Message Filtering