| name | abp-app-nolayers |
| license | UNLICENSED |
| description | Use when working with the single-layer web application template or when the project has no layered separation. Covers single project structure, feature-based file organization, and no separate Domain/Application.Contracts projects. |
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<T, TKey> 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.
public class Book : AuditedAggregateRoot<Guid>
{
public string Name { get; set; }
public decimal Price { get; set; }
}
No Custom Repository Needed
Use generic repository directly - no need to define custom interfaces:
public class BookAppService : ApplicationService
{
private readonly IRepository<Book, Guid> _bookRepository;
}