Microservices in C# (.NET): From Theory to Practice
In modern software development, microservice architecture has become the standard for building scalable and fault-tolerant systems. The .NET platform provides all the necessary tools for creating reliable microservices in C#. In this article, we will explore key architectural principles, practical code examples, and best practices that will help you start building microservices in C#.
1. Fundamentals of Microservice Architecture in .NET
Microservices is a development approach where an application is divided into small, independent services, each responsible for its own business function. In the .NET ecosystem, ASP.NET Core is used for this purpose — a lightweight and cross-platform framework.
Key Principles of Microservices in C#:
- Independent deployment — each service can be updated without stopping others.
- Loose coupling — services communicate via API (REST, gRPC) or message queues.
- Own database — each microservice owns its data (Database per Service).
- Fault tolerance — failure of one service should not block the entire system.
Let's start by creating a simple microservice in C#. We'll use the ASP.NET Core Web API template.
// Creating a new microservice projectdotnet new webapi -n OrderServicecd OrderService
// Example of a simple controller[ApiController][Route("api/[controller]")]public class OrdersController : ControllerBase{ private readonly IOrderRepository _repository;
public OrdersController(IOrderRepository repository) { _repository = repository; }
[HttpGet("{id}")] public async Task<IActionResult> GetOrder(int id) { var order = await _repository.GetByIdAsync(id); if (order == null) return NotFound(); return Ok(order); }
[HttpPost] public async Task<IActionResult> CreateOrder(OrderDto orderDto) { var order = new Order(orderDto.CustomerId, orderDto.TotalAmount); await _repository.AddAsync(order); return CreatedAtAction(nameof(GetOrder), new { id = order.Id }, order); }}2. Inter-Service Communication: REST, gRPC, and Queues
Microservices need to communicate with each other. In .NET, three main approaches are available:
REST API (HTTP)
The simplest and most common method. Use HttpClient with a factory for proper connection management.
// Example of calling another microservice via HttpClientpublic class InventoryServiceClient{ private readonly HttpClient _httpClient;
public InventoryServiceClient(HttpClient httpClient) { _httpClient = httpClient; }
public async Task<bool> CheckStockAsync(int productId, int quantity) { var response = await _httpClient.GetAsync( $"/api/inventory/check?productId={productId}&quantity={quantity}"); return response.IsSuccessStatusCode; }}
// Registration in Program.csbuilder.Services.AddHttpClient<InventoryServiceClient>(client =>{ client.BaseAddress = new Uri("http://inventory-service:5001");});gRPC
For high-performance synchronous communication, use gRPC. It is based on HTTP/2 and Protocol Buffers.
// Service definition in .proto filesyntax = "proto3";
service OrderProcessor { rpc ProcessOrder (OrderRequest) returns (OrderResponse);}
message OrderRequest { int32 order_id = 1; string customer_email = 2;}
message OrderResponse { bool success = 1; string message = 2;}
// Server-side implementation in C#public class OrderProcessorService : OrderProcessor.OrderProcessorB