IConfiguration vs IOptions NET
Synchronous and Asynchronous in .NET Core
Model Binding and Validation in ASP.NET Core
ControllerBase vs Controller in ASP.NET Core
ConfigureServices and Configure methods
IHostedService interface in .NET Core
ASP.NET Core request processing
| GraphQL APIs in .NET Core | Communication Between Microservices | |
Asynchronous Messaging in .NET Core ๐ |
Asynchronous messaging is a communication pattern where a sender posts a message to a destination (typically a message broker) without waiting for an immediate response. One or more receivers can then consume and process that message at their own pace. This pattern is fundamental to modern, distributed architectures like microservices, as it enables services to operate independently and improves overall resilience and scalability.
A common way to implement asynchronous messaging in .NET Core is by using RabbitMQ, a popular open-source message broker. The following example demonstrates a publish-subscribe (pub/sub) pattern where an OrderService publishes an event, and a NotificationService consumes it.
First, ensure a RabbitMQ message broker is running. A Docker container is a convenient way to do this for development.
//shell docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management
Create a shared class library project to define the message format, ensuring both the publisher and consumer use the same contract.
//csharp
// Shared/OrderCreatedEvent.cs
public class OrderCreatedEvent
{
public Guid OrderId { get; set; }
public string CustomerEmail { get; set; }
}
This service creates a connection to RabbitMQ, declares an exchange, and publishes the OrderCreatedEvent when a new order is processed.
//csharp
// In OrderService project
using RabbitMQ.Client;
using System.Text.Json;
using System.Text;
using Shared;
public class OrderProducer : IDisposable
{
private readonly IConnection _connection;
private readonly IModel _channel;
public OrderProducer()
{
var factory = new ConnectionFactory() { HostName = "localhost" };
_connection = factory.CreateConnection();
_channel = _connection.CreateModel();
// Fanout exchange sends a message to all bound queues
_channel.ExchangeDeclare(exchange: "order-exchange", type: ExchangeType.Fanout);
}
public void PublishOrderCreated(Guid orderId, string customerEmail)
{
var orderEvent = new OrderCreatedEvent { OrderId = orderId, CustomerEmail = customerEmail };
var message = JsonSerializer.Serialize(orderEvent);
var body = Encoding.UTF8.GetBytes(message);
_channel.BasicPublish(
exchange: "order-exchange",
routingKey: string.Empty, // Ignored by fanout exchanges
basicProperties: null,
body: body);
Console.WriteLine($"Order {orderId} published to RabbitMQ.");
}
public void Dispose()
{
_channel?.Close();
_connection?.Close();
}
}
This service creates a connection, declares a queue, and subscribes to the order-exchange to receive notifications.
//csharp
// In NotificationService project
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;
using System.Text.Json;
using Shared;
public class NotificationConsumer : BackgroundService
{
private readonly IConnection _connection;
private readonly IModel _channel;
public NotificationConsumer()
{
var factory = new ConnectionFactory() { HostName = "localhost" };
_connection = factory.CreateConnection();
_channel = _connection.CreateModel();
_channel.ExchangeDeclare(exchange: "order-exchange", type: ExchangeType.Fanout);
// Declare an anonymous, auto-deleting queue and bind it
var queueName = _channel.QueueDeclare().QueueName;
_channel.QueueBind(queue: queueName, exchange: "order-exchange", routingKey: string.Empty);
}
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
stoppingToken.ThrowIfCancellationRequested();
var consumer = new EventingBasicConsumer(_channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body.ToArray();
var message = Encoding.UTF8.GetString(body);
var orderEvent = JsonSerializer.Deserialize<OrderCreatedEvent>(message);
Console.WriteLine($"Notification received for order {orderEvent.OrderId} to {orderEvent.CustomerEmail}");
};
_channel.BasicConsume(queue: _channel.QueueName, autoAck: true, consumer: consumer);
return Task.CompletedTask;
}
}
| GraphQL APIs in .NET Core | Communication Between Microservices | |