--- description: "ABP Single-Layer (No-Layers) application template specific patterns" globs: - "**/src/*/*Module.cs" - "**/src/*/Entities/**/*.cs" - "**/src/*/Services/**/*.cs" - "**/src/*/Data/**/*.cs" alwaysApply: false --- # ABP Single-Layer Application Template > **Docs**: https://abp.io/docs/latest/solution-templates/single-layer-web-application ## Solution Structure Single project containing everything: ``` MyProject/ ├── src/ │ └── MyProject/ │ ├── Data/ # DbContext, migrations │ ├── Entities/ # Domain entities │ ├── Services/ # Application services + DTOs │ ├── Pages/ # Razor pages / Blazor components │ └── MyProjectModule.cs └── test/ └── MyProject.Tests/ ``` ## Key Differences from Layered | Layered Template | Single-Layer Template | |------------------|----------------------| | DTOs in Application.Contracts | DTOs in Services folder (same project) | | Repository interfaces in Domain | Use generic `IRepository` directly | | Separate Domain.Shared for constants | Constants in same project | | Multiple module classes | Single module class | ## File Organization Group related files by feature: ``` Services/ ├── Books/ │ ├── BookAppService.cs │ ├── BookDto.cs │ ├── CreateBookDto.cs │ └── IBookAppService.cs └── Authors/ ├── AuthorAppService.cs └── ... ``` ## Simplified Entity (Still keep invariants) Single-layer templates are structurally simpler, but you may still have real business invariants. - For **trivial CRUD** entities, public setters can be acceptable. - For **non-trivial business rules**, still prefer encapsulation (private setters + methods) to prevent invalid states. ```csharp public class Book : AuditedAggregateRoot { public string Name { get; set; } // OK for trivial CRUD only public decimal Price { get; set; } } ``` ## No Custom Repository Needed Use generic repository directly - no need to define custom interfaces: ```csharp public class BookAppService : ApplicationService { private readonly IRepository _bookRepository; // Generic repository is sufficient for single-layer apps } ```