Building Lightweight Microservices with .NET 8 Minimal APIs
Discover how .NET 8 Minimal APIs let you build lightweight microservices with a single file, built‑in DI, and simple validation. Learn setup, routing, trade‑offs, and how to verify your service.
21 Jan 2026, 15:16 UTC

Why Minimal APIs for Microservices?
When you need a fast‑to‑spin microservice that can be deployed in seconds, the boilerplate of MVC controllers can feel like a hurdle. Minimal APIs cut that overhead by letting you write endpoints directly in Program.cs with top‑level statements. The result is a single file that still has full access to ASP.NET Core’s dependency injection, configuration, and middleware pipeline.
Setting Up a Minimal Project
Start with the bare‑bones template:
dotnet new web -n MinimalDemo -f net8.0
cd MinimalDemo
Open Program.cs and replace its contents with the following example. It demonstrates routing, DI, logging, and a simple validation step.
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using FluentValidation;
using FluentValidation.Results;
var builder = WebApplication.CreateBuilder(args);
// 1. Register services
builder.Services.AddSingleton<IWeatherService, WeatherService>();
builder.Services.AddSingleton<ILogger<WeatherService>, Logger<WeatherService>>();
builder.Services.AddValidatorsFromAssemblyContaining<WeatherRequestValidator>();
var app = builder.Build();
// 2. Middleware pipeline
app.UseHttpsRedirection();
app.UseAuthentication(); // optional – add policies as needed
app.UseAuthorization();
// 3. Define endpoints
app.MapGet("/weather", async (ILogger<WeatherService> logger, IWeatherService weather) =>
{
var forecast = await weather.GetForecastAsync();
logger.LogInformation("Returned forecast for {Date}", forecast.Date);
return Results.Ok(forecast);
});
app.MapPost("/weather", async (WeatherRequest request, IValidator<WeatherRequest> validator) =>
{
ValidationResult result = await validator.ValidateAsync(request);
if (!result.IsValid)
{
return Results.ValidationProblem(result.ToDictionary());
}
return Results.Ok("Weather data accepted");
});
app.Run();
// 4. Domain types
public record WeatherRequest(string City, int Days);
public record WeatherForecast(DateTime Date, string Summary, int TemperatureC);
public interface IWeatherService
{
Task<WeatherForecast> GetForecastAsync();
}
public class WeatherService : IWeatherService
{
private readonly ILogger<WeatherService> _logger;
public WeatherService(ILogger<WeatherService> logger) => _logger = logger;
public Task<WeatherForecast> GetForecastAsync() => Task.FromResult(
new WeatherForecast(DateTime.UtcNow, "Sunny", 25));
}
public class WeatherRequestValidator : AbstractValidator<WeatherRequest>
{
public WeatherRequestValidator()
{
RuleFor(r => r.City).NotEmpty();
RuleFor(r => r.Days).InclusiveBetween(1, 7);
}
}
Routing & Dependency Injection
Endpoints are defined with MapGet and MapPost, which automatically bind route parameters and request bodies. The framework resolves IWeatherService and ILogger from the built‑in DI container, so you can keep your services separate from the endpoint logic.
Validation Made Simple
The example uses FluentValidation to validate the WeatherRequest. Because the validator is registered as a service, the endpoint receives it automatically. If validation fails, the framework returns a 422 ValidationProblem with a dictionary of errors.
Trade‑offs & Limitations
- Structure: Large codebases can become hard to navigate without the traditional controller‑action separation.
- Routing Flexibility: Attribute routing is not available; all routes are convention‑based. For legacy APIs you may need to write custom middleware.
- Security: Authentication and authorization are not automatically applied. Forgetting to add
app.UseAuthentication()or policies can leave endpoints exposed. - Future Syntax: Source generators for routing are experimental and might alter the current API surface in later releases.
How to Verify Your Setup
- Run the service:
dotnet run.- Check that
https://localhost:5001/weatherreturns a JSON forecast. - Post a valid
WeatherRequestJSON to/weatherand confirm a 200 response. - Post an invalid request (e.g., missing
City) and verify a 422 with validation errors.
- Check that
- Measure performance: use
wrkorabto compare latency against an MVC controller. - Test security: add
app.UseAuthentication()and a simple policy, then attempt an unauthenticated request to ensure a 401 is returned.
Actionable Checklist
- Start with
dotnet new weband target .NET 8 LTS. - Define endpoints in
Program.csusingMapGet/MapPost. - Register services, logging, and validators in the builder.
- Add authentication/authorization middleware early in the pipeline.
- Use
Results.ValidationProblemfor consistent error responses. - Document your routing conventions so new developers understand the structure.
Minimal APIs give you a lean, testable microservice that starts working in minutes. For small to medium services, the reduced boilerplate outweighs the structural trade‑offs. If you need more complex routing or a monolithic architecture, consider a hybrid approach: keep the core logic in services and expose them via minimal endpoints.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.