Introduction to Microservices in C#
Microservice Architecture (MSA) is a software development approach where an application is built as a set of small, independently deployable services. Each service implements one business capability, has its own database, and can be written in different languages. However, in the .NET ecosystem, the C# platform and ASP.NET Core provide some of the best tools for building reliable microservices.
In this article, we will cover the full cycle of creating microservices in C#: from architecture design to deployment in containers. You will learn how to organize communication between services, ensure their fault tolerance and scalability.
1. Designing Microservice Architecture in .NET
The first step is to properly break down a monolithic application into services. A good practice is to follow the Domain-Driven Design (DDD) principle and identify Bounded Contexts.
1.1. Defining Service Boundaries
Each microservice should be responsible for one business entity or process. For example, for an online store, you can identify:
- Catalog Service — product management
- Order Service — order processing
- Payment Service — payments
- Notification Service — notifications
Important: each service owns its own database. This prevents coupling and allows services to be scaled independently.
1.2. ASP.NET Core Project Structure
A typical C# microservice consists of several layers:
- API Layer — controllers and middleware
- Application Layer — CQRS, MediatR, commands and queries
- Domain Layer — entities, value objects, aggregates
- Infrastructure Layer — repositories, DbContext, external services
Example of a minimal directory structure:
MyMicroservice/├── MyMicroservice.Api/│ └── Controllers/├── MyMicroservice.Application/│ └── Commands/├── MyMicroservice.Domain/│ └── Entities/└── MyMicroservice.Infrastructure/ └── Data/2. Implementing a Microservice in C#: Practical Example
Let's create a simple service for managing a product catalog using ASP.NET Core 8 and Entity Framework Core.
2.1. Setting up WebApplication
In the Program.cs file, we configure the minimal API:
var builder = WebApplication.CreateBuilder(args);
// Add servicesbuilder.Services.AddDbContext<CatalogDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("CatalogDb")));
builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(Program).Assembly));
builder.Services.AddEndpointsApiExplorer();builder.Services.AddSwaggerGen();
var app = builder.Build();
// Middlewareif (app.Environment.IsDevelopment()){ app.UseSwagger(); app.UseSwaggerUI();}
app.UseHttpsRedirection();
// Minimal API endpointapp.MapGet("/api/products", async (IMediator mediator) =>{ var products = await mediator.Send(new GetProductsQuery()); return Results.Ok(products);});
app.Run();2.2. Data Model and CQRS
Create the Product entity:
public class Product{ public Guid Id { get; set; } public string Name { get; set; } = string.Empty; public decimal Price { get; set; } public string Category { get; set; } = string.Empty;}Use the CQRS pattern with MediatR to separate commands and queries:
public record GetProductsQuery() : IRequest<List<Product>>;
public class GetProductsHandler : IRequestHandler<GetProduc