ASP.NET - Hexagonal Architecture (Ports and Adapters) in ASP.NET Core – Detailed Explanation
Hexagonal Architecture, also known as the Ports and Adapters pattern, is a software design approach that focuses on separating the core business logic of an application from external concerns such as databases, user interfaces, and third-party services. The primary goal is to make the application more maintainable, testable, and adaptable to change.
1. Core Concept
At the center of Hexagonal Architecture lies the application core, which contains the business logic and domain rules. This core is completely independent of external systems. Instead of directly interacting with databases or APIs, it communicates through well-defined interfaces called ports.
External systems interact with the core through adapters, which implement these ports. This structure forms a hexagon-like shape conceptually, where each side represents a different interaction point.
2. Key Components
a. Domain (Core)
This is the heart of the application. It includes:
-
Business entities
-
Value objects
-
Domain services
-
Business rules
The domain layer does not depend on any external frameworks or libraries.
b. Ports
Ports are interfaces that define how the core interacts with the outside world. There are two types:
-
Inbound Ports (Driving Ports)
These define how external systems can interact with the application. For example:-
Application services
-
Use case interfaces
-
-
Outbound Ports (Driven Ports)
These define how the application interacts with external systems. For example:-
Repository interfaces
-
External service interfaces
-
c. Adapters
Adapters are implementations of the ports. They act as a bridge between the application core and external systems.
-
Inbound Adapters
-
Controllers (Web API)
-
UI components
-
CLI interfaces
-
-
Outbound Adapters
-
Database implementations (Entity Framework Core)
-
API clients
-
File systems
-
Messaging systems
-
3. How It Works in ASP.NET Core
In an ASP.NET Core application, Hexagonal Architecture can be implemented by structuring the project into multiple layers:
Example Structure
-
Domain Layer
-
Application Layer
-
Infrastructure Layer
-
Presentation Layer
Flow of Execution
-
A request comes into a controller (inbound adapter).
-
The controller calls an application service via an inbound port.
-
The application service executes business logic using domain models.
-
If data access is needed, it calls a repository interface (outbound port).
-
The actual repository implementation (outbound adapter) interacts with the database.
-
The result flows back to the controller and then to the client.
4. Example
Domain Layer
public class Order
{
public int Id { get; set; }
public decimal Amount { get; set; }
public bool IsValid()
{
return Amount > 0;
}
}
Outbound Port
public interface IOrderRepository
{
void Save(Order order);
}
Application Service (Inbound Port Implementation)
public class OrderService
{
private readonly IOrderRepository _repository;
public OrderService(IOrderRepository repository)
{
_repository = repository;
}
public void CreateOrder(Order order)
{
if (!order.IsValid())
throw new Exception("Invalid order");
_repository.Save(order);
}
}
Outbound Adapter
public class OrderRepository : IOrderRepository
{
public void Save(Order order)
{
// Database logic using EF Core
}
}
Inbound Adapter (Controller)
[ApiController]
[Route("api/orders")]
public class OrderController : ControllerBase
{
private readonly OrderService _service;
public OrderController(OrderService service)
{
_service = service;
}
[HttpPost]
public IActionResult Create(Order order)
{
_service.CreateOrder(order);
return Ok();
}
}
5. Advantages
-
Loose Coupling
The core logic is independent of frameworks and external tools. -
Testability
You can test business logic without needing a database or web server. -
Flexibility
You can replace external systems (database, UI) without changing the core. -
Maintainability
Changes in one part of the system do not affect others significantly.
6. Comparison with Traditional Layered Architecture
In traditional layered architecture:
-
Business logic often depends on infrastructure.
-
Changes in database or frameworks can impact core logic.
In hexagonal architecture:
-
Dependencies are inverted.
-
Core logic depends only on interfaces, not implementations.
7. When to Use Hexagonal Architecture
-
Large enterprise applications
-
Systems requiring high maintainability
-
Applications expected to evolve over time
-
Projects involving multiple integrations (APIs, messaging, etc.)
8. Challenges
-
Initial setup can be complex
-
Requires disciplined structure and understanding
-
May feel over-engineered for small applications
9. Summary
Hexagonal Architecture in ASP.NET Core emphasizes a clean separation between business logic and external systems using ports and adapters. It promotes a highly modular, testable, and scalable design, making it especially suitable for modern enterprise applications where flexibility and long-term maintainability are critical.