Onion Architecture - E-commerce Application
1. Domain Layer (Core of the Onion)
This layer contains the business rules and domain entities. It's the most important layer because it doesn't depend on any other layer.
Entities represent the core objects of the application, such as Customer, Product, and Order.
Customer Entity
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public Address Address { get; set; }
public bool IsEligibleForDiscount()
{
// Example business rule
return this.Name.StartsWith("A");
}
}
Product Entity
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public bool IsAvailable()
{
return Price > 0;
}
}
Order Entity
public class Order
{
public int Id { get; set; }
public Customer Customer { get; set; }
public List<Product> Products { get; set; }
public decimal TotalAmount { get; set; }
public void CalculateTotalAmount()
{
this.TotalAmount = Products.Sum(p => p.Price);
}
}
2. Application Layer (Use Cases Layer)
This layer contains the application logic that orchestrates the interaction between domain entities to perform use cases.
In our example, a use case could be placing an order.
PlaceOrderUseCase
public interface IPlaceOrderUseCase
{
void Execute(Order order);
}
public class PlaceOrderUseCase : IPlaceOrderUseCase
{
private readonly IOrderRepository _orderRepository;
private readonly ICustomerRepository _customerRepository;
public PlaceOrderUseCase(IOrderRepository orderRepository, ICustomerRepository customerRepository)
{
_orderRepository = orderRepository;
_customerRepository = customerRepository;
}
public void Execute(Order order)
{
order.CalculateTotalAmount();
if (order.Customer.IsEligibleForDiscount())
{
// Apply discount logic
}
_orderRepository.Save(order);
}
}
3. Infrastructure Layer (Interface Layer)
The infrastructure layer interacts with external systems like databases, file systems, third-party services, etc. It implements the interfaces defined in the application layer.
Repositories
Repositories handle data persistence. Below is an implementation of the IOrderRepository interface from the application layer.
Order Repository Interface (Application Layer).
public interface IOrderRepository
{
void Save(Order order);
Order Get(int orderId);
}
Order Repository Implementation (Infrastructure Layer).
public class OrderRepository : IOrderRepository
{
private readonly DatabaseContext _context;
public OrderRepository(DatabaseContext context)
{
_context = context;
}
public void Save(Order order)
{
_context.Orders.Add(order);
_context.SaveChanges();
}
public Order Get(int orderId)
{
return _context.Orders.FirstOrDefault(o => o.Id == orderId);
}
}
Customer Repository Interface (Application Layer).
public interface ICustomerRepository
{
Customer GetById(int customerId);
}
Customer Repository Implementation (Infrastructure Layer).
public class CustomerRepository : ICustomerRepository
{
private readonly DatabaseContext _context;
public CustomerRepository(DatabaseContext context)
{
_context = context;
}
public Customer GetById(int customerId)
{
return _context.Customers
.FirstOrDefault(c => c.Id == customerId);
}
}
4. Presentation Layer (UI Layer)
This is the user interface layer where interactions happen. It communicates with the application layer to perform actions like placing an order.
OrderController
public class OrderController : Controller
{
private readonly IPlaceOrderUseCase _placeOrderUseCase;
public OrderController(IPlaceOrderUseCase placeOrderUseCase)
{
_placeOrderUseCase = placeOrderUseCase;
}
public IActionResult PlaceOrder(Order order)
{
_placeOrderUseCase.Execute(order);
return View("OrderConfirmation", order);
}
}
Order Confirmation
- Order ID: @Model.Id
- Total Amount: @Model.TotalAmount
How the Layers Interact?
The layers communicate as follows.
- UI Layer (Controller): Receives the user input (e.g., clicking "Place Order") and calls the PlaceOrderUseCase.
- Application Layer (Use Case): Orchestrates business logic (e.g., calculating total, checking for discounts, saving order).
- Infrastructure Layer (Repository): This handles data persistence (e.g., saving the order to the database).
- Domain Layer (Entities): Contains business logic (e.g., validating discounts, calculating order total).