Building Efficient Microservices with .NET 🏗️

Apurv upadhyay
3 min readOct 13, 2024

--

Microservices enable scalable and independent service deployment, especially when built with .NET. Let’s break down the essential components you need for a smooth microservices architecture.

1️⃣ Create Modular Independent Services

Each microservice should be independent and serve a specific functionality. Here’s an example of a Product Service that only handles product-related logic.

[ApiController]
[Route("api/[controller]")]
public class ProductController : ControllerBase
{
[HttpGet("{id}")]
public IActionResult GetProductById(int id)
{
// Logic to retrieve product by ID
return Ok(new { Id = id, Name = "Smartphone", Price = 499.99 });
}

[HttpPost]
public IActionResult AddProduct([FromBody] Product product)
{
// Logic to add a new product
return CreatedAtAction(nameof(GetProductById), new { id = product.Id }, product);
}
}

This service is completely independent and can be deployed separately from other services like orders or users.

2️⃣ Implement an API Gateway

The API Gateway is responsible for routing requests to the correct microservices. Below is an example using YARP (Yet Another Reverse Proxy) to route requests to various microservices.

// Program.cs in your API Gateway
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}

// Startup.cs configuration for YARP
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddReverseProxy()
.LoadFromConfig(Configuration.GetSection("ReverseProxy"));
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapReverseProxy();
});
}
}

YARP Configuration (appsettings.json)

"ReverseProxy": {
"Routes": {
"product-route": {
"ClusterId": "product-cluster",
"Match": { "Path": "/api/products/{**catch-all}" }
}
},
"Clusters": {
"product-cluster": {
"Destinations": {
"product-api": { "Address": "http://localhost:5002/" }
}
}
}
}

This configuration routes all product requests through the gateway and directs them to the Product Service running on port 5002.

3️⃣ Service Communication

Microservices often need to communicate with each other. You can use various protocols such as HTTP, gRPC, or message queues to ensure smooth communication.

Using RabbitMQ for Event-Driven Communication:

Here’s an example of using RabbitMQ to publish and consume messages between services.

// Publisher Service (e.g., Order Service)
public class OrderPublisher
{
private readonly IConnection _connection;
private readonly IModel _channel;

public OrderPublisher()
{
var factory = new ConnectionFactory() { HostName = "localhost" };
_connection = factory.CreateConnection();
_channel = _connection.CreateModel();
_channel.QueueDeclare(queue: "orderQueue", durable: false, exclusive: false, autoDelete: false, arguments: null);
}

public void PublishOrder(Order order)
{
var message = JsonConvert.SerializeObject(order);
var body = Encoding.UTF8.GetBytes(message);
_channel.BasicPublish(exchange: "", routingKey: "orderQueue", basicProperties: null, body: body);
}
}

// Consumer Service (e.g., Inventory Service)
public class OrderConsumer
{
private readonly IConnection _connection;
private readonly IModel _channel;

public OrderConsumer()
{
var factory = new ConnectionFactory() { HostName = "localhost" };
_connection = factory.CreateConnection();
_channel = _connection.CreateModel();
_channel.QueueDeclare(queue: "orderQueue", durable: false, exclusive: false, autoDelete: false, arguments: null);
}

public void StartConsuming()
{
var consumer = new EventingBasicConsumer(_channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body.ToArray();
var message = Encoding.UTF8.GetString(body);
var order = JsonConvert.DeserializeObject<Order>(message);
Console.WriteLine($"Order Received: {order.Id}");
};
_channel.BasicConsume(queue: "orderQueue", autoAck: true, consumer: consumer);
}
}

In this example, the Order Service publishes messages (orders) to RabbitMQ, and the Inventory Service listens for new orders and consumes them.

Are you building microservices with .NET? Share your tips and challenges with us below!

Feel free to repost ♻️ if you found this helpful. For more great content on microservices, follow 🛠 Apurv Upadhyay.

#Microservices #DotNet #EventDriven #RabbitMQ #Cloud

--

--

Apurv upadhyay
Apurv upadhyay

Written by Apurv upadhyay

Principal Software Engineer at PeerIslands • Microsoft Azure Certified Architect Expert & DevOps Specialist • 7x Azure Certified • ex-Microsoft, Bosch

No responses yet