Microservices in C#: Architecture and Practice for .NET Developers

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Microservices in C#: From Theory to Practice on .NET



Microservice architecture has become the standard for building scalable and fault-tolerant applications. The .NET (C#) platform provides all the necessary tools for creating such systems: from built-in containerization support to powerful frameworks for inter-service communication. In this article, we will break down the key principles of building microservices in C# and look at practical code examples.



1. Fundamentals of Microservice Architecture on .NET



Microservices is an approach where an application is divided into independent, loosely coupled services. Each service is responsible for its own business function and can be developed, deployed, and scaled independently of others.



Key principles for a .NET developer:

  • Single Responsibility — each microservice solves one task.
  • Data Independence — each service has its own database (Database per Service).
  • Loose Coupling — services communicate via API, not through shared memory.
  • Autonomy — a service can be changed and redeployed without stopping the entire system.


To create a new microservice project in C#, use the command:

dotnet new webapi -n UserServicedotnet new webapi -n OrderServicedotnet new webapi -n NotificationService


Each project gets its own Program.cs, configurations, and dependencies.



2. Inter-service Communication: REST and gRPC



In .NET, there are two main approaches to communication between microservices: synchronous (REST/gRPC) and asynchronous (via message brokers). Let's look at both.



REST API using HttpClient

The simplest way is to use HttpClientFactory to create a typed client.



// In Program.cs of the OrderServicebuilder.Services.AddHttpClient<IUserServiceClient, UserServiceClient>(client =>{    client.BaseAddress = new Uri("http://userservice:5000");});

// UserServiceClient.cspublic class UserServiceClient : IUserServiceClient{ private readonly HttpClient _httpClient;

public UserServiceClient(HttpClient httpClient) { _httpClient = httpClient; }

public async Task<UserDto> GetUserAsync(int userId) { var response = await _httpClient.GetAsync($"/api/users/{userId}"); response.EnsureSuccessStatusCode(); return await response.Content.ReadFromJsonAsync<UserDto>(); }}


Recommendation: use Polly (a library for .NET) to implement retry policies and Circuit Breaker.



gRPC for High-Performance Scenarios

gRPC works over HTTP/2 and uses Protocol Buffers for serialization. This is significantly faster than JSON.



// Service definition in user.protoservice UserGrpcService {  rpc GetUser (GetUserRequest) returns (UserResponse);}

// Server code in C#public class UserGrpcServiceImpl : UserGrpcService.UserGrpcServiceBase{ public override Task<UserResponse> GetUser(GetUserRequest request, ServerCallContext context) { var user = _dbContext.Users.Find(request.UserId); return Task.FromResult(new UserResponse { Id = user.Id, Name = user.Name, Email = user.Email }); }}


3. Data Management and Transactions



In microservices, each database belongs to only one service. This eliminates direct SQL queries between services. For working with data in .NET, the standard is Entity Framework Core.



Example of DbContext Configuration for a Microservice

public cla                

Blogs

Book Recommendations