DEV Community

Cover image for Event Broker Implementation in C# Using Azure Service Bus
Daniel Azevedo
Daniel Azevedo

Posted on

Event Broker Implementation in C# Using Azure Service Bus

Hi devs

The Event Broker Pattern is an essential part of modern distributed systems, particularly for microservices. It serves as a mediator for communication between producers and consumers of events, ensuring decoupled and scalable systems.

In this post, we’ll implement the Event Broker Pattern using Azure Service Bus in a practical example involving an Order Service, Inventory Service, and Payment Service.


What Is an Event Broker?

An Event Broker is a centralized system that manages the routing of events from producers to consumers. Instead of services directly communicating with each other, they publish or subscribe to events via the broker.

In our implementation, the Azure Service Bus Topic acts as the Event Broker, managing the following:

  • Routing events to multiple subscribers.
  • Decoupling services, as they don’t need to know about each other.
  • Ensuring reliable delivery of messages.

How the Event Broker Works

In this example:

  1. Order Service acts as the event producer, publishing an event (OrderPlaced).
  2. Azure Service Bus acts as the event broker, routing events to subscribers.
  3. Inventory Service and Payment Service are the event consumers, processing the OrderPlaced event.

This architecture ensures scalability, as new consumers can be added without modifying the producer.


Step-by-Step Implementation

Here’s how to set up and implement the pattern.


Step 1: Prerequisites

  1. Azure Setup:

    • Create a Service Bus Namespace in the Azure Portal.
    • Add a Topic named OrdersTopic.
    • Add Subscriptions: InventorySubscription and PaymentSubscription.
  2. Development Setup:

    • Create a new .NET project:
     dotnet new console -n EventBrokerExample
    
  • Install the Azure.Messaging.ServiceBus package:

     dotnet add package Azure.Messaging.ServiceBus
    

Step 2: Define a Shared Order Model

public class Order
{
    public int Id { get; set; }
    public int ProductId { get; set; }
    public int Quantity { get; set; }
    public decimal TotalPrice { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

This model will represent the data passed between the services.


Step 3: Implement the Event Producer (Order Service)

The Order Service publishes events to the Azure Service Bus Topic.

using Azure.Messaging.ServiceBus;
using System.Text.Json;

public class OrderPublisher
{
    private readonly ServiceBusSender _sender;

    public OrderPublisher(string connectionString, string topicName)
    {
        var client = new ServiceBusClient(connectionString);
        _sender = client.CreateSender(topicName);
    }

    public async Task PublishOrderPlacedEventAsync(Order order)
    {
        var message = new ServiceBusMessage(JsonSerializer.Serialize(order))
        {
            Subject = "OrderPlaced"
        };
        await _sender.SendMessageAsync(message);
        Console.WriteLine($"Published OrderPlaced event for Order ID: {order.Id}");
    }
}

// Usage:
var connectionString = "<YourServiceBusConnectionString>";
var topicName = "OrdersTopic";

var publisher = new OrderPublisher(connectionString, topicName);
var order = new Order { Id = 1, ProductId = 101, Quantity = 2, TotalPrice = 50.00m };
await publisher.PublishOrderPlacedEventAsync(order);
Enter fullscreen mode Exit fullscreen mode

This sends an event to the Event Broker (Service Bus Topic).


Step 4: Implement the Event Consumers

Inventory Service

The Inventory Service subscribes to the OrderPlaced event and updates stock.

using Azure.Messaging.ServiceBus;
using System.Text.Json;

public class InventoryService
{
    private readonly ServiceBusProcessor _processor;

    public InventoryService(string connectionString, string topicName, string subscriptionName)
    {
        var client = new ServiceBusClient(connectionString);
        _processor = client.CreateProcessor(topicName, subscriptionName, new ServiceBusProcessorOptions());
    }

    public void Start()
    {
        _processor.ProcessMessageAsync += OnMessageReceived;
        _processor.ProcessErrorAsync += OnError;
        _processor.StartProcessingAsync();
    }

    private async Task OnMessageReceived(ProcessMessageEventArgs args)
    {
        var order = JsonSerializer.Deserialize<Order>(args.Message.Body.ToString());
        Console.WriteLine($"InventoryService processing Order ID: {order.Id}");
        Console.WriteLine($"Reducing stock for Product ID: {order.ProductId}");
        await args.CompleteMessageAsync(args.Message);
    }

    private Task OnError(ProcessErrorEventArgs args)
    {
        Console.WriteLine($"Error: {args.Exception.Message}");
        return Task.CompletedTask;
    }
}

// Usage:
var inventoryService = new InventoryService("<YourServiceBusConnectionString>", "OrdersTopic", "InventorySubscription");
inventoryService.Start();
Enter fullscreen mode Exit fullscreen mode
Payment Service

The Payment Service processes the payment for the order.

using Azure.Messaging.ServiceBus;
using System.Text.Json;

public class PaymentService
{
    private readonly ServiceBusProcessor _processor;

    public PaymentService(string connectionString, string topicName, string subscriptionName)
    {
        var client = new ServiceBusClient(connectionString);
        _processor = client.CreateProcessor(topicName, subscriptionName, new ServiceBusProcessorOptions());
    }

    public void Start()
    {
        _processor.ProcessMessageAsync += OnMessageReceived;
        _processor.ProcessErrorAsync += OnError;
        _processor.StartProcessingAsync();
    }

    private async Task OnMessageReceived(ProcessMessageEventArgs args)
    {
        var order = JsonSerializer.Deserialize<Order>(args.Message.Body.ToString());
        Console.WriteLine($"PaymentService processing Order ID: {order.Id}");
        Console.WriteLine($"Processing payment of {order.TotalPrice:C}");
        await args.CompleteMessageAsync(args.Message);
    }

    private Task OnError(ProcessErrorEventArgs args)
    {
        Console.WriteLine($"Error: {args.Exception.Message}");
        return Task.CompletedTask;
    }
}

// Usage:
var paymentService = new PaymentService("<YourServiceBusConnectionString>", "OrdersTopic", "PaymentSubscription");
paymentService.Start();
Enter fullscreen mode Exit fullscreen mode

How It All Works

  1. Order Service publishes an OrderPlaced event to the Service Bus Topic.
  2. Azure Service Bus (Event Broker) forwards the event to all subscribers.
  3. Inventory Service updates the stock.
  4. Payment Service processes the payment.

Benefits of This Approach

  1. Decoupling: Each service is independent and doesn’t directly call others.
  2. Scalability: Multiple consumers can process events concurrently.
  3. Flexibility: Adding new consumers requires no changes to existing producers.
  4. Reliability: Azure Service Bus ensures message delivery with retries.

Conclusion

The Event Broker Pattern simplifies communication between microservices, making systems more scalable and maintainable. Using Azure Service Bus makes it even easier to implement this architecture with minimal effort.

Keep coding :)

Top comments (0)