This skill guides implementation of domain-driven design and clean architecture patterns in ASP.NET Core Web APIs, following the strategic and tactical patterns from Eric Evans' "Domain-Driven Design" and the architectural principles from Robert C. Martin's "Clean Architecture".
The user provides backend requirements: a feature, bounded context, aggregate, or architectural refactoring to implement. They may include domain context, business rules, or technical constraints.
Strategic Design Principles
Before coding, understand the domain and establish clear boundaries:
- Ubiquitous Language: Identify key domain terms and use them consistently in code, comments, and conversations
- Bounded Contexts: Define clear boundaries where a domain model applies. Each bounded context has its own model and language
- Context Mapping: Understand relationships between bounded contexts (Shared Kernel, Customer-Supplier, Anti-Corruption Layer, etc.)
- Core Domain: Identify what makes the business unique and valuable. Invest the most effort here
- Subdomains: Distinguish between Core, Supporting, and Generic subdomains to allocate appropriate design effort
Clean Architecture Layers
Organize code into layers with clear dependency rules (dependencies point inward):
1. Domain Layer (Innermost - No Dependencies)
- Entities: Objects with identity that persist through time and state changes
- Value Objects: Immutable objects defined by their attributes, not identity
- Aggregates: Cluster of entities and value objects with a root entity enforcing invariants
- Domain Events: Events that domain experts care about
- Domain Services: Operations that don't belong to a single entity
- Specifications: Business rule predicates that can be combined and reused
- Enumerations: Domain-specific enumeration types (use strongly-typed enums)
2. Application Layer (Orchestration - Depends on Domain)
- Use Cases/Commands: Application-specific business operations (CQRS commands)
- Queries: Read operations returning DTOs (CQRS queries)
- Application Services: Coordinate use cases, manage transactions
- DTOs: Data transfer objects for crossing boundaries
- Interfaces: Repository interfaces, external service interfaces (defined here, implemented in Infrastructure)
- Validators: Input validation using FluentValidation
3. Infrastructure Layer (External - Depends on Application & Domain)
- Persistence: EF Core DbContext, repository implementations
- External Services: API clients, message queues, email services
- Identity & Security: Authentication, authorization implementations
- Caching: Redis, in-memory cache implementations
- File Storage: Blob storage, file system operations
- Configuration: Options pattern implementations
4. Presentation Layer (API - Depends on Application)
- Controllers: Thin controllers that delegate to application layer
- Minimal APIs: Endpoint definitions (if using minimal API pattern)
- Middleware: Cross-cutting concerns (logging, exception handling)
- Filters: Action filters, exception filters
- Models: API request/response models (different from DTOs)
Tactical DDD Patterns Implementation
Entities
- Entities have identity that persists through time and state changes
- Follow the entity base class pattern established in the project
- Implement equality based on identity (Id property)
- Encapsulate business rules and invariants within entities
Value Objects
- Use C# records for immutable value objects
- Define value objects by their attributes, not identity
- Records provide structural equality by default
- Keep value objects simple and focused on domain concepts
Aggregates
- Identify aggregate boundaries based on transactional consistency needs
- Ensure one root entity per aggregate
- Enforce invariants in the aggregate root
- Reference other aggregates by identity only
- Keep aggregates small and focused
Domain Events
- Define domain events for important business occurrences
- Raise events within entities/aggregates when state changes occur
- Handle events at the application layer for cross-aggregate coordination
Repository Pattern
- Define specific repository interfaces for each aggregate root
- Place interfaces in the Application or Domain layer
- Implement repositories in the Infrastructure layer using EF Core
- Avoid generic repositories - create focused, aggregate-specific repositories
- Repository methods should reflect domain operations, not just CRUD
Result Pattern
- Use ErrorOr library for operation outcomes
- Return
ErrorOr<T> from application services and use cases
- Avoid exceptions for flow control
- Provide meaningful error types for different failure scenarios
Essential NuGet Packages
- ErrorOr: For error handling and result pattern
- FluentValidation: For input validation
- Entity Framework Core: For persistence
Implementation Guidelines
- Start with the Domain: Model the core domain first, independent of infrastructure
- Protect Invariants: Encapsulate business rules within entities and aggregates
- Explicit is Better: Make implicit concepts explicit (value objects, domain events)
- Persistence Ignorance: Domain layer should not depend on ORM or database concerns
- Dependency Inversion: High-level modules should not depend on low-level modules
- Unit of Work: Manage transactions at the application layer
- Thin Controllers: Controllers should only validate, delegate, and return results
- Avoid Anemic Models: Put behavior in the domain, not just in services
- Test Domain Logic: Focus testing efforts on domain and application layers
- Evolution: Design should evolve with understanding; refactor as knowledge grows
Anti-Patterns to Avoid
- Anemic Domain Model: Entities with only getters/setters and no behavior
- Transaction Script: Business logic scattered in service classes
- God Aggregate: Aggregates that are too large and do too much
- Repository Overload: Repositories with dozens of query methods
- Infrastructure Leakage: Domain layer depending on infrastructure concerns
- CRUD Thinking: Modeling operations as simple create/read/update/delete
- Generic Repositories: Abstraction that doesn't add value and hinders querying
- MediatR Overuse: Don't use MediatR unless explicitly requested - keep it simple
src/
├── Domain/
│ ├── Common/
│ │ ├── Entity.cs
│ │ ├── ValueObject.cs
│ │ └── DomainEvent.cs
│ ├── Orders/
│ │ ├── Order.cs (Aggregate Root)
│ │ ├── OrderItem.cs (Entity)
│ │ ├── Money.cs (Value Object)
│ │ └── Events/
│ │ └── OrderPlacedEvent.cs
│ └── Customers/
├── Application/
│ ├── Common/
│ │ ├── Behaviors/
│ │ └── Interfaces/
│ ├── Orders/
│ │ ├── Commands/
│ │ ├── Queries/
│ │ └── DTOs/
│ └── DependencyInjection.cs
├── Infrastructure/
│ ├── Persistence/
│ │ ├── ApplicationDbContext.cs
│ │ ├── Configurations/
│ │ └── Repositories/
│ ├── Services/
│ └── DependencyInjection.cs
└── WebApi/
├── Controllers/
├── Middleware/
└── Program.cs
Remember: DDD is about modeling complex domains. If the domain is simple (CRUD), don't over-engineer. Apply DDD patterns where complexity justifies the investment. Clean architecture provides structure; DDD provides rich domain modeling within that structure.
1---2name: ddd-clean-architecture3description: Implement domain-driven design (DDD) and clean architecture patterns in ASP.NET Core Web APIs. Use this skill when building or refactoring backend services that need strategic domain modeling, tactical DDD patterns (entities, value objects, aggregates, domain events, repositories), and clean architecture layers (domain, application, infrastructure, presentation). Follows principles from Eric Evans' "Domain-Driven Design" and Robert C. Martin's "Clean Architecture".4license: Complete terms in LICENSE.txt5---6
7This skill guides implementation of domain-driven design and clean architecture patterns in ASP.NET Core Web APIs, following the strategic and tactical patterns from Eric Evans' "Domain-Driven Design" and the architectural principles from Robert C. Martin's "Clean Architecture".
8
9The user provides backend requirements: a feature, bounded context, aggregate, or architectural refactoring to implement. They may include domain context, business rules, or technical constraints.
10
11## Strategic Design Principles
12
13Before coding, understand the domain and establish clear boundaries:
14
15- **Ubiquitous Language**: Identify key domain terms and use them consistently in code, comments, and conversations
16- **Bounded Contexts**: Define clear boundaries where a domain model applies. Each bounded context has its own model and language
17- **Context Mapping**: Understand relationships between bounded contexts (Shared Kernel, Customer-Supplier, Anti-Corruption Layer, etc.)
18- **Core Domain**: Identify what makes the business unique and valuable. Invest the most effort here
19- **Subdomains**: Distinguish between Core, Supporting, and Generic subdomains to allocate appropriate design effort
20
21## Clean Architecture Layers
22
23Organize code into layers with clear dependency rules (dependencies point inward):
24
25### 1. Domain Layer (Innermost - No Dependencies)
26
27- **Entities**: Objects with identity that persist through time and state changes
28- **Value Objects**: Immutable objects defined by their attributes, not identity
29- **Aggregates**: Cluster of entities and value objects with a root entity enforcing invariants
30- **Domain Events**: Events that domain experts care about
31- **Domain Services**: Operations that don't belong to a single entity
32- **Specifications**: Business rule predicates that can be combined and reused
33- **Enumerations**: Domain-specific enumeration types (use strongly-typed enums)
34
35### 2. Application Layer (Orchestration - Depends on Domain)
36
37- **Use Cases/Commands**: Application-specific business operations (CQRS commands)
38- **Queries**: Read operations returning DTOs (CQRS queries)
39- **Application Services**: Coordinate use cases, manage transactions
40- **DTOs**: Data transfer objects for crossing boundaries
41- **Interfaces**: Repository interfaces, external service interfaces (defined here, implemented in Infrastructure)
42- **Validators**: Input validation using FluentValidation
43
44### 3. Infrastructure Layer (External - Depends on Application & Domain)
45
46- **Persistence**: EF Core DbContext, repository implementations
47- **External Services**: API clients, message queues, email services
48- **Identity & Security**: Authentication, authorization implementations
49- **Caching**: Redis, in-memory cache implementations
50- **File Storage**: Blob storage, file system operations
51- **Configuration**: Options pattern implementations
52
53### 4. Presentation Layer (API - Depends on Application)
54
55- **Controllers**: Thin controllers that delegate to application layer
56- **Minimal APIs**: Endpoint definitions (if using minimal API pattern)
57- **Middleware**: Cross-cutting concerns (logging, exception handling)
58- **Filters**: Action filters, exception filters
59- **Models**: API request/response models (different from DTOs)
60
61## Tactical DDD Patterns Implementation
62
63### Entities
64
65- Entities have identity that persists through time and state changes
66- Follow the entity base class pattern established in the project
67- Implement equality based on identity (Id property)
68- Encapsulate business rules and invariants within entities
69
70### Value Objects
71
72- Use C# records for immutable value objects
73- Define value objects by their attributes, not identity
74- Records provide structural equality by default
75- Keep value objects simple and focused on domain concepts
76
77### Aggregates
78
79- Identify aggregate boundaries based on transactional consistency needs
80- Ensure one root entity per aggregate
81- Enforce invariants in the aggregate root
82- Reference other aggregates by identity only
83- Keep aggregates small and focused
84
85### Domain Events
86
87- Define domain events for important business occurrences
88- Raise events within entities/aggregates when state changes occur
89- Handle events at the application layer for cross-aggregate coordination
90
91### Repository Pattern
92
93- Define specific repository interfaces for each aggregate root
94- Place interfaces in the Application or Domain layer
95- Implement repositories in the Infrastructure layer using EF Core
96- Avoid generic repositories - create focused, aggregate-specific repositories
97- Repository methods should reflect domain operations, not just CRUD
98
99### Result Pattern
100
101- Use ErrorOr library for operation outcomes
102- Return `ErrorOr<T>` from application services and use cases
103- Avoid exceptions for flow control
104- Provide meaningful error types for different failure scenarios
105
106## Essential NuGet Packages
107
108- **ErrorOr**: For error handling and result pattern
109- **FluentValidation**: For input validation
110- **Entity Framework Core**: For persistence
111
112## Implementation Guidelines
113
1141. **Start with the Domain**: Model the core domain first, independent of infrastructure
1152. **Protect Invariants**: Encapsulate business rules within entities and aggregates
1163. **Explicit is Better**: Make implicit concepts explicit (value objects, domain events)
1174. **Persistence Ignorance**: Domain layer should not depend on ORM or database concerns
1185. **Dependency Inversion**: High-level modules should not depend on low-level modules
1196. **Unit of Work**: Manage transactions at the application layer
1207. **Thin Controllers**: Controllers should only validate, delegate, and return results
1218. **Avoid Anemic Models**: Put behavior in the domain, not just in services
1229. **Test Domain Logic**: Focus testing efforts on domain and application layers
12310. **Evolution**: Design should evolve with understanding; refactor as knowledge grows
124
125## Anti-Patterns to Avoid
126
127- **Anemic Domain Model**: Entities with only getters/setters and no behavior
128- **Transaction Script**: Business logic scattered in service classes
129- **God Aggregate**: Aggregates that are too large and do too much
130- **Repository Overload**: Repositories with dozens of query methods
131- **Infrastructure Leakage**: Domain layer depending on infrastructure concerns
132- **CRUD Thinking**: Modeling operations as simple create/read/update/delete
133- **Generic Repositories**: Abstraction that doesn't add value and hinders querying
134- **MediatR Overuse**: Don't use MediatR unless explicitly requested - keep it simple
135
136```console
137src/
138├── Domain/
139│ ├── Common/
140│ │ ├── Entity.cs
141│ │ ├── ValueObject.cs
142│ │ └── DomainEvent.cs
143│ ├── Orders/
144│ │ ├── Order.cs (Aggregate Root)
145│ │ ├── OrderItem.cs (Entity)
146│ │ ├── Money.cs (Value Object)
147│ │ └── Events/
148│ │ └── OrderPlacedEvent.cs
149│ └── Customers/
150├── Application/
151│ ├── Common/
152│ │ ├── Behaviors/
153│ │ └── Interfaces/
154│ ├── Orders/
155│ │ ├── Commands/
156│ │ ├── Queries/
157│ │ └── DTOs/
158│ └── DependencyInjection.cs
159├── Infrastructure/
160│ ├── Persistence/
161│ │ ├── ApplicationDbContext.cs
162│ │ ├── Configurations/
163│ │ └── Repositories/
164│ ├── Services/
165│ └── DependencyInjection.cs
166└── WebApi/
167 ├── Controllers/
168 ├── Middleware/
169 └── Program.cs
170```
171
172Remember: DDD is about modeling complex domains. If the domain is simple (CRUD), don't over-engineer. Apply DDD patterns where complexity justifies the investment. Clean architecture provides structure; DDD provides rich domain modeling within that structure.