Member-only story
Onion and Clean Architecture in .NET C#: From Palermo’s rings to Clean solution templates (2026)
Imagine your e-commerce has been running on ports and adapters for a few months. (If you want to find out more about the Hexagonal Architecture, click here.) The payment gateway is behind an interface, the database is behind a repository, and the team is proud of it. Then the team grows from three developers to eight, and a code review finds this in the project that was supposed to be the core:
// Naive approach - What NOT to do: a "core" that knows its surroundings
public sealed class PlaceOrderUseCase(ShopDbContext db, IHttpContextAccessor http)
{
public async Task<IResult> ExecuteAsync(PlaceOrderRequest request, CancellationToken cancellationToken)
{
var customerId = Guid.Parse(http.HttpContext!.User.FindFirst("sub")!.Value);
var product = await db.Products.FindAsync([request.ProductId], cancellationToken);
if (product is null)
return Results.NotFound();
// ... stock, coupon, payment, order and email, all written against EF Core and HTTP
var order = Order.Draft(customerId, DateTimeOffset.UtcNow);
db.Orders.Add(order);
await db.SaveChangesAsync(cancellationToken);
return Results.Created($"/orders/{order.Id}", new { order.Id });
}
}Nobody decided this. Someone needed the user id, injected the accessor and moved on. But look at what the “core” now knows: EF Core, HTTP, and it answers with a status code. The result?










