Vertical Slice Architecture in ASP.NET Core: organizing code by feature with minimal APIs

.NET Architecture & Design Patterns November 13, 2026 csharp

Organization by feature: each use case keeps its endpoint, request, validation, handler and data access together.

csharp
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// ======================================================================
// Q: What is Vertical Slice Architecture?
//
// Organization by feature: each use case keeps its endpoint, request,
// validation, handler and data access together. A change touches one place, not
// five layers.
// - Each slice chooses its own complexity: a simple query goes straight to the
//   DbContext, a complex command goes through the domain model.
// - Risk: duplicated rules. Shared business rules belong in the domain, not in
//   every slice.
// - It combines well with Clean Architecture: the Domain / Infrastructure
//   boundaries stay, and inside Application the code is organized by feature.
// ======================================================================

// Feature folder layout and a GetOrderById slice
Features/
  Orders/
    CreateOrder.cs        // request + validator + handler + endpoint
    CancelOrder.cs
    GetOrderById.cs
  Catalog/
    SearchProducts.cs

public static class GetOrderById
{
    public record Response(int Id, string Number, decimal Total);

    public static void Map(IEndpointRouteBuilder app) =>
        app.MapGet("/orders/{id:int}", Handle).RequireAuthorization();

    private static async Task<Results<Ok<Response>, NotFound>> Handle(
        int id, AppDbContext db, CancellationToken ct)
    {
        var dto = await db.Orders.AsNoTracking()
            .Where(o => o.Id == id)
            .Select(o => new Response(o.Id, o.OrderNumber, o.TotalNet))
            .FirstOrDefaultAsync(ct);
        return dto is null ? TypedResults.NotFound() : TypedResults.Ok(dto);
    }
}