A modern .NET 10 API solution built with Clean Architecture principles, Domain-Driven Design (DDD), and orchestrated with .NET Aspire for cloud-ready microservices development.
π Note: This project is based on the Ardalis Clean Architecture Template, I adjusted a little bit in Presentention Layer by group into folder (It's just personal preference). For more information about the template and its design decisions, please visit the official repository.
This project implements Clean Architecture with a hybrid approach combining:
- Clean Architecture for core business logic and application layers
- Vertical Slice Architecture for API endpoints using FastEndpoints
- Domain-Driven Design (DDD) patterns in the domain layer
- .NET Aspire for distributed application orchestration
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Presentation Layer β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Aiva.Admin.Api.Web (FastEndpoints) β β
β β - API Endpoints (Vertical Slices) β β
β β - Request/Response DTOs β β
β β - Validators β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Application Layer β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Aiva.Admin.Api.UseCases (CQRS Pattern) β β
β β - Commands (Create, Update, Delete) β β
β β - Queries (Get, List) β β
β β - DTOs and Mappers β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Domain Layer β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Aiva.Admin.Api.Core (Business Logic) β β
β β - Entities & Aggregates β β
β β - Value Objects β β
β β - Domain Events β β
β β - Specifications β β
β β - Domain Services β β
β β - Repository Interfaces β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β²
β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Infrastructure Layer β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Aiva.Admin.Api.Infrastructure β β
β β - EF Core DbContext & Repositories β β
β β - Database Migrations β β
β β - External Service Implementations β β
β β - Email Services (Papercut/MimeKit) β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- Aiva.Admin.Api.AspireHost: Orchestration layer using .NET Aspire for managing distributed services and dependencies
- Aiva.Admin.Api.ServiceDefaults: Shared service configurations (OpenTelemetry, health checks, logging)
Aiva.Admin.Api/
β
βββ src/
β βββ Aiva.Admin.Api.AspireHost/ # .NET Aspire orchestration
β β βββ Program.cs # Service orchestration configuration
β β βββ Properties/launchSettings.json # Launch profiles (including WSL support)
β β
β βββ Aiva.Admin.Api.Web/ # API Presentation Layer
β β βββ Contributors/ # Feature: Contributor endpoints (Vertical Slices)
β β β βββ Create/ # Create contributor endpoint + validator
β β β βββ Update/ # Update contributor endpoint + validator
β β β βββ Delete/ # Delete contributor endpoint + validator
β β β βββ Get/ # Get by ID endpoint + validator
β β β βββ List/ # List contributors endpoint + validator
β β βββ Configurations/ # Startup configurations
β β βββ Program.cs # Application entry point
β β
β βββ Aiva.Admin.Api.UseCases/ # Application Layer (Use Cases)
β β βββ Contributors/ # Contributor use cases (CQRS)
β β β βββ Create/ # CreateContributorCommand + Handler
β β β βββ Update/ # UpdateContributorCommand + Handler
β β β βββ Delete/ # DeleteContributorCommand + Handler
β β β βββ Get/ # GetContributorQuery + Handler
β β β βββ List/ # ListContributorsQuery + Handler
β β β βββ ContributorDTO.cs # Shared DTO
β β βββ PagedResult.cs # Pagination support
β β
β βββ Aiva.Admin.Api.Core/ # Domain Layer
β β βββ ContributorAggregate/ # Contributor aggregate root
β β β βββ Contributor.cs # Entity with business rules
β β β βββ ContributorId.cs # Strongly-typed ID (Value Object)
β β β βββ ContributorName.cs # Value Object
β β β βββ PhoneNumber.cs # Value Object
β β β βββ ContributorStatus.cs # Enumeration
β β β βββ Events/ # Domain events
β β β βββ Handlers/ # Domain event handlers
β β β βββ Specifications/ # Query specifications
β β βββ Interfaces/ # Repository & service abstractions
β β βββ Services/ # Domain services
β β
β βββ Aiva.Admin.Api.Infrastructure/ # Infrastructure Layer
β β βββ Data/
β β β βββ AppDbContext.cs # EF Core DbContext
β β β βββ EfRepository.cs # Generic repository implementation
β β β βββ EventDispatcherInterceptor.cs # Domain event dispatcher
β β β βββ Migrations/ # EF Core migrations
β β β βββ Config/ # Entity configurations
β β β βββ Queries/ # Read-optimized queries
β β βββ Email/ # Email service implementations
β β
β βββ Aiva.Admin.Api.ServiceDefaults/ # Shared configurations
β βββ Extensions.cs # OpenTelemetry, health checks, etc.
β
βββ tests/
βββ Aiva.Admin.Api.UnitTests/ # Unit tests (15 tests)
β βββ Core/ # Domain model tests
β βββ UseCases/ # Use case handler tests
β
βββ Aiva.Admin.Api.IntegrationTests/ # Integration tests
β βββ Data/ # Repository & database tests
β
βββ Aiva.Admin.Api.FunctionalTests/ # End-to-end API tests (3 tests)
β βββ ApiEndpoints/ # API endpoint tests
β βββ CustomWebApplicationFactory.cs # Testcontainers setup
β
βββ Aiva.Admin.Api.AspireTests/ # Aspire orchestration tests
βββ AspireIntegrationTests.cs # Service startup & health tests
- .NET 10 - Latest .NET platform
- C# 13 - Latest C# language features
- ASP.NET Core - Web framework
- Clean Architecture - Separation of concerns with dependency inversion
- Domain-Driven Design (DDD) - Rich domain models with aggregates and value objects
- CQRS - Command Query Responsibility Segregation pattern
- Vertical Slice Architecture - Feature-focused endpoint organization
- FastEndpoints - High-performance, developer-friendly alternative to MVC controllers
- Swagger/OpenAPI - API documentation and testing
- MediatR - Mediator pattern implementation for CQRS
- FluentValidation - Validation library integrated with FastEndpoints
- Ardalis.Result - Result pattern for better error handling
- Ardalis.Specification - Repository pattern with specification support
- Ardalis.GuardClauses - Guard clauses for defensive programming
- Ardalis.SmartEnum - Type-safe enum alternatives
- Entity Framework Core - ORM for database access
- SQL Server - Primary database (via Aspire orchestration)
- SQLite - Fallback database for standalone runs
- MimeKit - Email sending
- Papercut SMTP - Email testing during development
- .NET Aspire - Cloud-ready application orchestration
- OpenTelemetry - Distributed tracing and metrics
- Serilog - Structured logging
- xUnit - Test framework
- FluentAssertions - Fluent assertion library
- Testcontainers - Docker containers for integration testing
- Moq/NSubstitute - Mocking libraries
- Dependency Rule: Dependencies point inward toward the domain
- Core business logic has no dependencies on external frameworks
- Infrastructure and UI depend on abstractions defined in Core
- Aggregates: Related entities grouped together (e.g., Contributor aggregate)
- Value Objects: Immutable objects representing domain concepts (e.g., ContributorName, PhoneNumber)
- Domain Events: Communicate changes within the domain
- Specifications: Reusable query logic encapsulated in the domain
- Commands: Mutate state (Create, Update, Delete)
- Queries: Fetch data without side effects (Get, List)
- Clear separation improves testability and scalability
- Each feature endpoint contains:
- Request/Response models
- Validators
- Endpoint handler
- Reduces coupling between features
- Makes features easier to understand and modify
- Value objects validate data at construction time
- Invalid objects cannot exist in the system
- Type safety at compile time
- .NET 9 SDK - Download
- Docker Desktop - Required for .NET Aspire containers and Testcontainers
- Visual Studio 2022 (v17.12+) or Visual Studio Code with C# extensions
- SQL Server Management Studio (optional) - For database inspection
-
Clone the repository
git clone <repository-url> cd Aiva.Admin.Api
-
Restore dependencies
dotnet restore
-
Build the solution
dotnet build
This will start SQL Server and Papercut containers automatically:
# Set AspireHost as startup project and run
cd src/Aiva.Admin.Api.AspireHost
dotnet runThe Aspire Dashboard will open in your browser showing:
- SQL Server container (port 1433)
- Papercut SMTP server (SMTP: port 25, UI: port 37408)
- Web API application
- Health checks, metrics, and distributed tracing
Access Points:
- Aspire Dashboard:
https://localhost:17021(or as shown in console) - Web API:
https://localhost:7071orhttp://localhost:5071 - Swagger UI:
https://localhost:7071/swagger - Papercut Email UI:
http://localhost:37408
This will use SQLite as the database:
cd src/Aiva.Admin.Api.Web
dotnet runAccess Points:
- Web API:
https://localhost:7071 - Swagger UI:
https://localhost:7071/swagger
- Set
Aiva.Admin.Api.AspireHostas the startup project - Press F5 or click "Start Debugging"
- The Aspire Dashboard will automatically open
Migrations are applied automatically on application startup. To create new migrations:
# From the solution root
cd src/Aiva.Admin.Api.Web
# Create a new migration
dotnet ef migrations add MigrationName \
-c AppDbContext \
-p ../Aiva.Admin.Api.Infrastructure/Aiva.Admin.Api.Infrastructure.csproj \
-s Aiva.Admin.Api.Web.csproj \
-o Data/Migrations
# Apply migrations manually (if needed)
dotnet ef database update \
-c AppDbContext \
-p ../Aiva.Admin.Api.Infrastructure/Aiva.Admin.Api.Infrastructure.csproj \
-s Aiva.Admin.Api.Web.csprojIf you're using Docker in WSL, use the WSL-specific launch profiles:
# From AspireHost directory
dotnet run --launch-profile https-wslOr in Visual Studio, select the https-wsl profile from the dropdown.
See Aspire Host README for detailed WSL configuration.
The solution includes comprehensive testing at multiple levels:
-
Unit Tests (
Aiva.Admin.Api.UnitTests) - 15 tests- Domain model tests (entities, value objects)
- Use case handler tests (isolated with mocks)
- Fast execution, no external dependencies
-
Integration Tests (
Aiva.Admin.Api.IntegrationTests)- Repository tests with real database
- Data access logic validation
- EF Core behavior verification
-
Functional Tests (
Aiva.Admin.Api.FunctionalTests) - 3 tests- End-to-end API endpoint testing
- Uses Testcontainers with SQL Server 2022
- Each test gets isolated containerized database
- Validates migrations work correctly
-
Aspire Tests (
Aiva.Admin.Api.AspireTests)- Service orchestration tests
- Container startup and health verification
# Run all tests
dotnet test
# Run specific test project
dotnet test tests/Aiva.Admin.Api.UnitTests
# Run with code coverage
dotnet test --collect:"XPlat Code Coverage"
# Run tests in parallel (configured via .runsettings)
dotnet test --settings .runsettingsThe solution is configured for parallel test execution:
- Test assemblies run in parallel (uses all CPU cores)
- Test collections within each assembly also run in parallel
- See PARALLEL_TEST_EXECUTION.md for configuration details
Functional tests use Testcontainers for realistic database testing:
- Real SQL Server 2022 running in Docker containers
- Automatic container lifecycle management
- Isolated database per test class
- See TESTCONTAINERS_IMPLEMENTATION.md for details
Requirements:
- Docker Desktop must be running
- First run downloads SQL Server image (~1.5 GB)
All endpoints follow RESTful conventions and are documented via Swagger.
| Method | Endpoint | Description |
|---|---|---|
| GET | /contributors |
List all contributors (with pagination) |
| GET | /contributors/{id} |
Get contributor by ID |
| POST | /contributors |
Create new contributor |
| PUT | /contributors/{id} |
Update existing contributor |
| DELETE | /contributors/{id} |
Delete contributor |
Sample Request (Create Contributor):
POST /contributors
{
"name": "John Doe",
"phoneNumber": "+1234567890",
"status": 1
}Sample Response:
{
"id": 1,
"name": "John Doe",
"phoneNumber": "+1234567890",
"status": 1
}Access the interactive API documentation at /swagger when running the application.
Additional documentation files:
- Aspire Host Configuration - .NET Aspire setup and WSL support
- Core Domain Layer - Domain model guidelines
- Infrastructure Layer - Database and external services
- Use Cases Layer - Application logic patterns
- Testcontainers Setup - Functional testing with Docker
- Parallel Test Execution - Test performance optimization
-
Create Domain Entities (
Coreproject)Core/ProjectAggregate/ βββ Project.cs # Aggregate root βββ ProjectId.cs # Value object βββ ProjectName.cs # Value object βββ Events/ # Domain events βββ Specifications/ # Query specifications -
Add Database Configuration (
Infrastructureproject)// Infrastructure/Data/Config/ProjectConfiguration.cs public class ProjectConfiguration : IEntityTypeConfiguration<Project>
-
Create Use Cases (
UseCasesproject)UseCases/Projects/ βββ ProjectDTO.cs βββ Create/ β βββ CreateProjectCommand.cs β βββ CreateProjectHandler.cs βββ List/ β βββ ListProjectsQuery.cs β βββ ListProjectsHandler.cs βββ ... -
Add API Endpoints (
Webproject)Web/Projects/ βββ Create/ β βββ Create.cs # FastEndpoint β βββ CreateProjectRequest.cs β βββ CreateProjectResponse.cs β βββ CreateProjectValidator.cs βββ List/ βββ ... -
Write Tests
- Unit tests for domain logic
- Integration tests for repositories
- Functional tests for API endpoints
-
Create Migration
dotnet ef migrations add AddProjectAggregate
- Follow C# coding conventions
- Use meaningful names (domain language)
- Keep methods small and focused
- Write tests before or alongside implementation
- Use guard clauses for validation
- Leverage value objects to avoid primitive obsession
This solution demonstrates enterprise-grade practices:
β
Separation of Concerns - Clear boundaries between layers
β
Dependency Inversion - Core depends on abstractions, not implementations
β
Testability - High test coverage with fast unit tests
β
Maintainability - Features organized by vertical slices
β
Observability - OpenTelemetry integration for distributed tracing
β
Container Ready - Docker support with .NET Aspire
β
Type Safety - Value objects and strongly-typed IDs
β
Domain-Centric - Business logic in domain layer, not scattered
β
CQRS - Optimized read and write paths
β
Realistic Testing - Testcontainers for database integration tests
- Create a feature branch
- Write tests for new functionality
- Ensure all tests pass
- Follow existing code structure and naming conventions
- Submit a pull request
See LICENSE file for details.
- Clean Architecture by Uncle Bob
- Ardalis Clean Architecture Template
- .NET Aspire Documentation
- FastEndpoints Documentation
- Domain-Driven Design
- CQRS Pattern
- Testcontainers
For questions or support:
- Check existing documentation in project README files
- Review architectural decision records
- Contact: NimblePros
Built with β€οΈ using Clean Architecture principles and modern .NET practices