DEV Community

Anton Martyniuk
Anton Martyniuk

Posted on Originally published at antondevtips.com

Building Event-Driven Microservices with Azure Service Bus in .NET

In Microservices Architecture, services need to communicate with each other.
The simplest approach is synchronous HTTP calls, but it creates tight coupling between services.
If one service is slow or unavailable, it affects all dependent services.

Message brokers solve this problem by enabling asynchronous, message-based communication between your services.
Services publish events to the broker, and other services consume them independently.

When you are working in Azure, you can use Azure Service Bus to implement a message broker.
It supports both point-to-point and publish-subscribe messaging patterns.

In this post, we will explore:

  • Azure Service Bus: Core Concepts
  • How To Create Azure Service Bus in Azure Portal
  • Setting Up Azure Service Bus with .NET Aspire
  • How to Publish and Consume Messages with Azure Service Bus
  • The Event-Driven Pipeline: Payments, Fraud Detection, and Notifications
  • Running the Application Locally with Azure Service Bus Emulator
  • Deploying Microservices to Azure with Aspire
  • Azure Service Bus vs Other Azure Messaging Services

Let's dive in.


👉 Read original article on my newsletter: https://antondevtips.com/blog/building-event-driven-microservices-with-azure-service-bus-in-dotnet

Azure Service Bus: Core Concepts

Azure Service Bus is a fully managed enterprise message broker in the Azure Cloud.
It supports two messaging patterns: Queues and Topics with Subscriptions.

Queues

Queues implement point-to-point communication.
One sender sends a message, and one receiver processes it.
Each message is consumed by exactly one consumer.

Use queues when a message should be processed by a single service.
For example, sending a stock update command to the Stocks service.

Topics with Subscriptions

Topics with Subscriptions implement publish-subscribe communication.
One sender publishes a message to a topic, and multiple subscribers can each receive a copy of that message.
Each subscription acts as its own virtual queue.

Use topics when multiple services need to react to the same event.
For example, when a payment is processed, both the Fraud Detection service and the Notifications service may need to be notified.

Our solution has five microservices that communicate through Azure Service Bus:

  • Product-Service - manages products and handles purchases
  • Stock-Service - manages product stock levels
  • Payment-Service - processes payments and tracks their status
  • FraudDetection-Service - analyzes payments for fraud risk
  • Notification-Service - sends email notifications

Here is the message flow:

When a user purchases a product:

  1. Product-Service publishes UpdateStockEvent to the update-stock queue and PurchaseCompletedEvent to the payment-created queue
  2. Stock-Service consumes from update-stock and updates the stock count
  3. Payment-Service consumes from payment-created, creates a payment record, and publishes PaymentRegisteredEvent to the payment-registered topic
  4. FraudDetection-Service subscribes to the payment-registered topic, analyzes the payment, and publishes FraudDecisionEvent to the fraud-decision queue
  5. Payment-Service consumes from fraud-decision, updates the payment status, and publishes PaymentProcessedEvent to the payment-processed topic
  6. Notification-Service subscribes to the payment-processed topic and sends a notification

In our project, we use both:

  • Queues for update-stock, payment-created, and fraud-decision (one sender, one receiver)
  • Topics for payment-registered and payment-processed (one sender, multiple receivers)

How Messages Flow Through Service Bus

When a consumer receives a message, Service Bus does not delete it immediately.
It locks the message and hides it from other consumers for a configurable lock duration.

The consumer has that time to process the message and complete the call.
If it completes successfully, Service Bus deletes the message.
If the handler throws or the lock expires, Service Bus releases the message and makes it available for retry.

Service Bus tracks how many times a message has been delivered using the delivery count.
When the delivery count exceeds MaxDeliveryCount (default: 10), Service Bus automatically moves the message to the dead-letter queue.

At-least-once delivery is the core guarantee Service Bus provides.
A message will be delivered at least once, but in rare cases it may be delivered more than once — for example, if a network failure prevents the completion acknowledgement from reaching the Service Bus.
Your consumers must be idempotent: processing the same message twice must produce the same result.

Dead-Letter Queue

Every queue and every topic subscription has a built-in dead-letter sub-queue (DLQ).
Messages end up in the DLQ when:

  • The delivery count exceeds MaxDeliveryCount
  • Your code explicitly calls DeadLetterMessageAsync — for example, when a message is malformed, and retrying is pointless
  • The message TTL (time-to-live) expires before it is consumed

The DLQ is permanent — messages do not expire there.
You can inspect, replay, or archive them using the Azure Portal.

In production, monitor the DLQ message count and set up alerts.
A growing DLQ means something in your pipeline is consistently failing.

Duplicate Detection

Service Bus can automatically discard duplicate messages within a configurable time window.
Enable it on a queue or topic at creation time.

Service Bus tracks messages by their MessageId.
If a message with the same MessageId arrives within the duplicate detection window (default: 10 minutes), Service Bus silently drops it.

Use duplicate detection when your producer may retry sending — for example, after a timeout or a transient network failure.

Message Sessions

Sessions enable ordered, grouped processing of related messages.
Set a SessionId on each message to group them together.

Service Bus guarantees that all messages with the same SessionId are processed in order by a single consumer at a time.
No two consumers can process messages from the same session simultaneously.

Use sessions when order matters — for example, processing all state transitions for the same payment in sequence.
Sessions require RequiresSession = true on the queue or subscription.

How To Create Azure Service Bus in Azure Portal

First, create a new Azure Service Bus namespace in the Azure Portal.

Go to the Azure Portal and search for "Service Bus":

Create a new Service Bus namespace with the following settings:

  • Resource group: Choose your resource group or create a new one
  • Namespace name: Choose a globally unique name
  • Location: Select the region closest to your services
  • Pricing tier: Select Standard

The pricing tier is important.
The Basic tier only supports queues.
If you need topics and subscriptions (which we do), you must use at least the Standard tier.

For most development and production workloads, Standard is sufficient.
Choose Premium only if you need dedicated resources, virtual network integration, or messages larger than 256 KB.


👉 Read original article on my newsletter: https://antondevtips.com/blog/building-event-driven-microservices-with-azure-service-bus-in-dotnet

Top comments (0)