Building Lightweight Services with ASP.NET Core Minimal APIs
Learn how to replace boilerplate controllers with Minimal APIs while keeping DI, routing, and middleware intact.
25 Dec 2025, 12:51 UTC

Problem: Too Much Ceremony for Simple Services
When you need a tiny HTTP endpoint — perhaps a health check, a webhook receiver, or a prototype API — creating a full MVC controller with its own class file, routing attributes, and a Startup/Program.cs setup can feel like overkill. The extra files add mental overhead and slow down iteration, especially in microservice‑oriented projects where many services are small and focused.
Thesis: Minimal APIs give you the power of ASP.NET Core without the boilerplate
ASP.NET Core Minimal APIs let you define route handlers directly in a single file using top‑level statements. You still get the built‑in dependency injection (DI) container, routing, model binding, validation, and content negotiation, but you eliminate the separate Startup class and controller classes. This approach is ideal for lightweight services while preserving the ability to add custom middleware or host‑builder configuration when the project grows.
How Minimal APIs Work
The WebApplicationBuilder created by WebApplication.CreateBuilder(args) configures the host, services, and logging just like the traditional Startup class. After building the app with builder.Build(), you register endpoints using methods on the returned WebApplication instance — for example, app.MapGet, app.MapPost, etc. Lambda expressions or local functions can receive injected services directly from the DI container, so you write something like app.MapGet("/hello", (IMyService svc) => svc.GetMessage());.
Worked Example: Hello Service with DI
Create a new web project (run in a folder where you have write permission):
Thedotnet new web -n MinimalApiDemo cd MinimalApiDemodotnet new webtemplate produces aProgram.cswith a basic minimal API.Define a simple service that will be injected into the handler. Replace the contents of
Program.cswith the following code:
This file uses top‑level statements, registersusing Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; var builder = WebApplication.CreateBuilder(args); // Register a scoped service builder.Services.AddScoped(); var app = builder.Build(); app.MapGet("/hello", (IMessageService svc) => Results.Ok(new { Message = svc.GetMessage() })); app.Run(); public interface IMessageService { string GetMessage(); } public class MessageService : IMessageService { public string GetMessage() => "Hello from a Minimal API!"; }IMessageServiceas a scoped service, and maps a GET endpoint that returns JSON.Run the service and verify the response:
The command prints the listening URLs, typically something likedotnet runhttp://localhost:5000andhttps://localhost:7001. Open a browser or usecurlto call the endpoint:
You should see a JSON payload similar to:curl http://localhost:5000/hello
If another process is already using port 5000, the SDK will choose a different port and display it in the console; adjust the URL accordingly.{ "message": "Hello from a Minimal API!" }Practical check: confirm DI works by changing the implementation of
MessageService.GetMessageto return a timestamp and re‑runningdotnet run. The updated value appears in the response without recompiling a separate controller class.
Trade‑off and Limitations
Minimal APIs excel at simplicity, but they are not a drop‑in replacement for every scenario:
Features that rely heavily on controller conventions — such as Razor view rendering, OData endpoints, or advanced API versioning — are either unavailable or require extra work.
Debugging inline lambdas can be harder because the handler code lives inside the
Program.csfile; stepping into a lambda may show less clear call stacks compared with a dedicated controller class.As the number of endpoints grows, a single file can become unwieldy. At that point, splitting handlers into separate classes (still using minimal API routing) or migrating to traditional controllers improves maintainability.
These limitations do not disqualify Minimal APIs for many microservices, internal tooling, or prototypes; they simply mean you should evaluate whether the reduced ceremony outweighs the need for advanced controller‑specific features.
Actionable Closing
If you are building a service that primarily exchanges JSON data and does not require server‑side views or complex versioning, start with a Minimal API. It gives you immediate access to ASP.NET Core’s robust DI, routing, and middleware pipeline while keeping the project footprint small. As the service evolves, you can extract handlers into separate classes or move to a controller‑based architecture without rewriting the core logic. Begin by running the commands above, inspect the JSON output, and decide whether the lightweight approach fits your current engineering decision.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.