Clean / Onion Architecture — Project Layer Mapping
This document maps the 9 csproj projects in SplitApp/ to the Onion architecture rings as taught in the TalTech lecture (courses.taltech.akaver.com/web-applications-with-csharp/lectures/architecture1).
The 9 projects
SplitApp/
├── Base.Contracts/ ← Domain Contracts (generic / cross-cutting, innermost)
├── Base.Domain/ ← Domain Primitives (cross-cutting)
├── Base.Helpers/ ← Infrastructure (cross-cutting helpers)
├── App.Domain/ ← Domain Layer (CORE)
├── App.DAL.EF/ ← Infrastructure (Data Access Layer)
├── App.BLL/ ← Application Services / Business Logic Layer
├── App.DTO/ ← Presentation Contracts (public API DTOs)
├── App.Resources/ ← Infrastructure (i18n / localization)
└── WebApp/ ← Presentation / UI (MVC + REST + Composition Root)
Onion Rings (innermost → outermost)
Ring 1 — Domain Model (CORE)
The innermost ring. Knows nothing about EF, ASP.NET, JWT, or any other technology.
| Project | Lecture name | Contents |
|---|---|---|
Base.Contracts |
Domain Contracts (generic / base) | IBaseEntity.cs, IBaseRepository.cs, IUnitOfWork.cs |
Base.Domain |
Domain Primitives / base entity classes | BaseEntity.cs (Id, CreatedAt, UpdatedAt), LangStr.cs (i18n value object) |
App.Domain |
Domain Entities + Domain Contracts (app-specific) | All concrete entities (Trip.cs, Expense, BudgetCategory, Currency, TripPoll, ...), enums (ETripStatus, EParticipantRole, ...), Identity/ (AppUser, AppRole, AppRefreshToken), and App.Domain/Contracts/ with IAppUnitOfWork, ITripRepository, IExpenseRepository, etc. |
Key rule: Repository interfaces (ITripRepository, IAppUnitOfWork) live in App.Domain/Contracts/, not in the DAL. That is the classical Onion rule — the inner ring defines the contract, the outer ring implements it, so dependencies always point inward.
Ring 2 — Application / BLL (Business Logic Layer)
Orchestrates use cases. Talks to the Domain only through the repository contracts in App.Domain/Contracts/.
| Project | Lecture name | Contents |
|---|---|---|
App.BLL |
Application Services / Business Logic Layer (BLL) | Services/ (ITripService + TripService, IExpenseService, IInvitationService, ...), Services/Admin/ (admin services), Services/Identity/ (IIdentityService — JWT issuing, refresh tokens), DTO/ (TripBllDto, ExpenseBllDto, BalanceBllDto, ...), Mappers/ (TripBllDtoFactory.Create(entity) and .ToEntity(dto)) |
Ring 3 — Infrastructure
Implements the contracts from the inner rings using concrete technologies (EF Core, JWT library, .NET resx).
| Project | Lecture name | Contents |
|---|---|---|
App.DAL.EF |
Infrastructure — Data Access Layer (EF Core implementation) | AppDbContext.cs (EF DbContext, IdentityDbContext), AppUnitOfWork.cs (implements IAppUnitOfWork), Repositories/* (concrete repos implementing the interfaces from App.Domain/Contracts/), Migrations/, Seeding/, ServiceCollectionExtensions.cs (AddDalServices), UtcDateTimeConverter.cs |
App.Resources |
Infrastructure — i18n / Localization resources | Domain/*.resx + *.et.resx, Common.resx, Views/Shared.resx, Domain/Enums.resx |
Base.Helpers |
Infrastructure — cross-cutting helpers | IdentityHelpers.cs (JWT generate/validate using System.IdentityModel.Tokens.Jwt) |
Note on DAL contracts placement: Akaver sometimes splits this into App.DAL.Contracts (interfaces) + App.DAL.EF (implementation). In this project the DAL contracts are inlined into App.Domain/Contracts/, which is also valid Onion — and arguably purer, because the contracts live in the Domain ring rather than in a separate "DAL contracts" project.
Ring 4 — Presentation / UI (outermost)
The composition root. Wires everything together.
| Project | Lecture name | Contents |
|---|---|---|
App.DTO |
Presentation Contracts (public API DTOs) | v1/TripDto.cs, v1/TripCreateDto.cs, v1/TripUpdateDto.cs, v1/Identity/* (LoginInfo, RegisterInfo, TokenRefreshInfo) |
WebApp |
Presentation / UI (MVC + REST API + Composition Root) | Program.cs (composition root), ApiControllers/ (versioned REST), Controllers/ (client MVC), Areas/Admin/Controllers/ + Areas/Admin/Views/ (admin MVC area), Areas/Identity/ (scaffolded Identity UI), Views/, ConfigureSwaggerOptions.cs, Helpers/ |
Dependency direction (must flow inward only)
WebApp ──────┐
├──► App.BLL ──► App.Domain ──► Base.Domain ──► Base.Contracts
App.DTO ─────┘ ▲
│ (App.Domain/Contracts/ITripRepository etc.)
App.DAL.EF ─────────────────────┘ implements those contracts
App.Resources, Base.Helpers ─── leaf utilities, used by outer rings
Verified in code: App.DAL.EF references App.Domain (so it can implement ITripRepository), but App.Domain does not reference App.DAL.EF. That is correct.
What "Infrastructure" means in this project
In the lecture's vocabulary, Infrastructure = anything that talks to the outside world or to a specific technology. In this project that is:
App.DAL.EF— primary infrastructure (EF Core, Postgres, migrations).App.Resources— secondary infrastructure (resx files for the .NET localization framework).Base.Helpers— JWT token plumbing (depends onSystem.IdentityModel.Tokens.Jwt, which is a tech-specific library).
Everything in those three projects can be swapped (e.g. switch from EF to Dapper, from resx to a translations DB, from JWT to OAuth) without touching App.Domain or App.BLL. That is the test of "is it infrastructure?".
Three-tier DTO flow
[ DB row ]
│ EF Core
▼
App.Domain.Trip ◄── domain entity (innermost)
│ TripBllDtoFactory.Create() in App.BLL/Mappers/
▼
App.BLL.DTO.TripBllDto ◄── BLL-internal DTO
│ inline mapping in WebApp/ApiControllers/TripsController.cs
▼
App.DTO.v1.TripDto ◄── public REST DTO (the wire format)
│ JSON
▼
[ HTTP response ]
- Entity ↔ BllDto mapper: App.BLL/Mappers/TripBllDtoFactory.cs
- BllDto ↔ public ApiDto mapper: currently inlined in the API controllers (no
WebApp/Mappers/folder exists yet).
Summary table — at a glance
| Onion ring | Lecture name | Project(s) |
|---|---|---|
| 1 (innermost) | Domain Contracts (generic) | Base.Contracts |
| 1 | Domain Primitives | Base.Domain |
| 1 | Domain Entities + app-specific Domain Contracts | App.Domain (incl. App.Domain/Contracts/) |
| 2 | Application Services / BLL | App.BLL |
| 3 | Infrastructure — DAL | App.DAL.EF |
| 3 | Infrastructure — i18n | App.Resources |
| 3 | Infrastructure — cross-cutting helpers | Base.Helpers |
| 4 | Presentation Contracts (public DTOs) | App.DTO |
| 4 (outermost) | Presentation / UI + Composition Root | WebApp |