| name | abp-dependency-rules |
| description | ABP Framework v10.x (10.4/10.5) layer dependency rules: layer direction (Domain.Shared→Domain→Application.Contracts→Application→HttpApi→Host), project reference matrix, anti-patterns (no DbContext in Application, don't expose IQueryable, don't return entity as DTO). Use when you need project/layer architecture or dependency rules in ABP. |
ABP Framework — Dependency Rules
ABP Framework v10.x (10.4/10.5) layer dependency rules and project-structure guardrails. Correct dependency direction, use of abstractions, and common violations.
Trigger
- "ABP layer architecture"
- "ABP dependency rules"
- "ABP layer dependency"
- "ABP project references"
- "ABP where is DbContext"
- "ABP architecture guardrail"
Core Principles (All Templates)
- Domain logic never depends on infrastructure (no DbContext in Domain/Application)
- Use abstractions (interfaces) for dependencies
- An upper layer depends on a lower layer, never the reverse
- Data access goes through the repository, not directly through DbContext
Layered Template Structure
Domain.Shared → Constants, enums, localization keys
↑
Domain → Entity, repository interface, domain service
↑
Application.Contracts → App service interface, DTO
↑
Application → App service implementation
↑
HttpApi → REST controller (optional)
↑
Host → Final application with DI + middleware
Reference Matrix
| Project | Can reference | Referenced by |
|---|
| Domain.Shared | (none) | All |
| Domain | Domain.Shared | Application, Data layer |
| Application.Contracts | Domain.Shared | Application, HttpApi, Clients |
| Application | Domain, Contracts | Host |
| EntityFrameworkCore / MongoDB | Domain | Host only |
| HttpApi | Contracts only | Host |
❌ Never Do
public class BookAppService : ApplicationService
{
private readonly MyDbContext _dbContext;
}
public class BookManager : DomainService
{
private readonly IBookAppService _appService;
}
public class BookController : AbpController
{
private readonly BookAppService _bookAppService;
}
✅ Always Do
public class BookAppService : ApplicationService
{
private readonly IBookRepository _bookRepository;
}
public class BookController : AbpController
{
private readonly IBookAppService _bookAppService;
}
Repository Location
public interface IBookRepository : IRepository<Book, Guid>
{
Task<Book> FindByNameAsync(string name);
}
public class BookRepository : EfCoreRepository<MyDbContext, Book, Guid>, IBookRepository { }
public class BookRepository : MongoDbRepository<MyDbContext, Book, Guid>, IBookRepository { }
Multiple Applications Scenario (Admin + Public)
MyProject.Admin.Application — Admin-specific services
MyProject.Public.Application — Public-specific services
MyProject.Domain — Shared domain (both reference it)
- The Admin and Public application layers DO NOT reference each other
- Domain logic is shared, application logic is not
- Each vertical can have its own DTO (even if similar)
Common Violations
| Violation | Impact | Solution |
|---|
| DbContext in Application | Breaks DB independence | Use a repository |
| Returning entity as DTO | Exposes internal structure | Map to a DTO |
IQueryable in interface | Breaks the abstraction | Return a concrete type |
| App service call across modules | Tight coupling | Use an event or domain |
Best Practices
- Stick to the dependency direction — top to bottom, never the reverse
- No DbContext in Domain/Application — only the repository abstraction
- Repository interface in Domain, implementation in the Data layer
- Don't expose
IQueryable — return a concrete type
- Don't let entities cross the boundary — always a DTO
- Use events/domain for cross-module communication — not a direct app service call
Related