The core (domain + use cases) doesn't know who calls it or what it calls.
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 | // ====================================================================== // Q: What is Hexagonal architecture (Ports and Adapters)? // // The core (domain + use cases) doesn't know who calls it or what it calls. It // communicates only through ports. // - Driving (primary) adapters: they call the core. REST endpoints, message // consumers, scheduled jobs, tests. // - Driven (secondary) adapters: the core calls them. EF repository, ERP client, // email sender. // Onion, Clean and Hexagonal share the same idea: an independent core and // dependency inversion. They differ in emphasis: layers (Onion), use cases // (Clean), inputs / outputs (Hexagonal). // ====================================================================== // Driven port: the core states what it needs public interface IErpGateway { Task<string> SendOrderAsync(Order o, CancellationToken ct); } public class SapErpAdapter(HttpClient http) : IErpGateway { /* SAP over HTTP */ } public class FakeErpAdapter : IErpGateway { /* for tests and local dev */ } // Two driving adapters, the same use case app.MapPost("/orders/{id}/sync", (int id, SyncOrderHandler h, CancellationToken ct) => h.Handle(id, ct)); public class OrderPlacedConsumer(SyncOrderHandler h) : IConsumer<OrderPlaced> { public Task Consume(ConsumeContext<OrderPlaced> ctx) => h.Handle(ctx.Message.OrderId, ctx.CancellationToken); } |