.NET  

How to Create Microservices in .NET: A Step-by-Step Guide

Introduction

Microservices architecture allows developers to build scalable, flexible, and independently deployable services. In the .NET ecosystem, creating microservices has become more accessible with modern tools like ASP.NET Core, Docker, and Kubernetes.

This article provides a step-by-step guide to building microservices in .NET, covering project setup, communication between services, and deployment practices.

🧱 What Are Microservices?

Microservices are small, autonomous services that work together. Each service is:

  • Focused on a single business capability.

  • Independently deployable.

  • Capable of running its own data and logic.

  • Communicating over lightweight protocols like HTTP or messaging queues.

🛠️ Step 1. Create the Solution and Projects

Use the CLI or Visual Studio to create a solution with multiple projects.

dotnet new sln -n MicroservicesDemo
cd MicroservicesDemo

# Create services
dotnet new webapi -n ProductService
dotnet new webapi -n OrderService

# Add to solution
dotnet sln add ProductService/ProductService.csproj
dotnet sln add OrderService/OrderService.csproj

🗃️ Step 2. Define the Project Structure

Typical structure for each microservice:

ProductService/
│
├── Controllers/
├── Models/
├── Data/
├── Services/
├── Program.cs
└── appsettings.json

Repeat the structure for OrderService.

📦 Step 3. Implement a Microservice (Example: ProductService)

Model: Product.cs

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}

DbContext: ProductContext.cs

public class ProductContext : DbContext
{
    public ProductContext(DbContextOptions<ProductContext> options) : base(options) { }
    public DbSet<Product> Products { get; set; }
}

Controller: ProductsController.cs

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    private readonly ProductContext _context;

    public ProductsController(ProductContext context) => _context = context;

    [HttpGet]
    public async Task<IEnumerable<Product>> Get() => await _context.Products.ToListAsync();
}

Register in Program.cs

builder.Services.AddDbContext<ProductContext>(opt =>
    opt.UseInMemoryDatabase("ProductDb"));
builder.Services.AddControllers();

🔗 Step 4. Communicate Between Microservices

There are several communication patterns:

1. HTTP REST (Simple)

Use HttpClient or Refit to call APIs between services.

public class ProductClient
{
    private readonly HttpClient _httpClient;

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

    public async Task<List<Product>> GetAllProductsAsync()
    {
        var response = await _httpClient.GetFromJsonAsync<List<Product>>("http://productservice/api/products");
        return response ?? new List<Product>();
    }
}

Register

builder.Services.AddHttpClient<ProductClient>();

2. gRPC (Efficient binary protocol)

  • Define .proto contracts.

  • Generate C# client/server.

  • Use gRPC template in .NET:

dotnet new grpc -n ProductGrpcService

3. Message Queue (Event-driven)

Use RabbitMQ, Azure Service Bus, or Kafka for async communication.

// Publish product created event
var factory = new ConnectionFactory() { HostName = "localhost" };
using var connection = factory.CreateConnection();
using var channel = connection.CreateModel();

channel.QueueDeclare(queue: "product-created");

var body = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new { Id = 1, Name = "Item" }));
channel.BasicPublish(exchange: "", routingKey: "product-created", body: body);

🧪 Step 5. Dockerize Your Services

Create Dockerfile in each microservice:

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "ProductService.dll"]

Then create docker-compose.yml to run all services:

version: '3.4'
services:
  productservice:
    build: ./ProductService
    ports:
      - "5001:80"
  orderservice:
    build: ./OrderService
    ports:
      - "5002:80"

Run

docker-compose up --build

🔐 Step 6. Secure Your Microservices

  • Use OAuth2 / JWT authentication (via IdentityServer or Auth0).

  • Validate JWT tokens in middleware:

builder.Services.AddAuthentication("Bearer")
    .AddJwtBearer("Bearer", options =>
    {
        options.Authority = "https://auth-server";
        options.Audience = "product-api";
    });

📈 Step 7. Observability and Monitoring

  • Logging: Serilog, ELK, or Seq.

  • Tracing: OpenTelemetry, Jaeger.

  • Health Checks:

builder.Services.AddHealthChecks();
app.MapHealthChecks("/health");

📦 Step 8. Deploy with Kubernetes (Optional)

If scaling is needed:

  • Write Deployment.yaml for each service.

  • Use kubectl apply -f deployment.yaml.

  • Use Ingress + Service mesh (like Istio) for routing and monitoring.

✅ Conclusion

Creating microservices in .NET involves:

  1. Building independent ASP.NET Core APIs.

  2. Managing communication via REST, gRPC, or messaging.

  3. Containerizing and orchestrating using Docker and Kubernetes.

  4. Securing and monitoring services for production readiness.

With this foundation, you can build scalable, maintainable microservices using the powerful .NET ecosystem.