This project serves as a learning exercise comparing C#/.NET development patterns with Java/Spring Boot, focusing on Clean Architecture principles and modern development practices.
A simple ASP.NET Core Web API for learning Entity Framework Core with Clean Architecture principles. Keep in mind that this is a simple project for educational purposes and many improvements can be made.
- .NET 8.0 - Target framework
- ASP.NET Core Web API - Web framework
- Entity Framework Core 8.0 - ORM with PostgreSQL provider
- PostgreSQL - Database (PostgreSQL 15)
- AutoMapper - Object-to-object mapping
- DotNetEnv - Environment variable loader
- Swagger/OpenAPI - API documentation (Swashbuckle.AspNetCore)
- xUnit v3 - Unit testing framework
- Coverlet - Code coverage analysis
- SonarCloud - Code quality and security analysis
- Docker - Containerization
- Keycloak - OAuth2/OIDC identity provider for authentication
- JWT Bearer - Token-based authentication
The project follows Clean Architecture principles with the following layers:
- Domain - Entities, interfaces, and domain exceptions
- Application - Services and application-specific logic
- Infrastructure - Data access, repositories, and external concerns
- Controllers - API endpoints and HTTP concerns
- User CRUD operations
- OAuth2/OIDC authentication with Keycloak
- JWT Bearer token validation
- JIT (Just-In-Time) user provisioning
- Email uniqueness validation
- Input validation
- Global exception handling
- Logging with structured logging
- Unit tests with high coverage
- API documentation with Swagger OAuth2 integration
- Docker support with full stack deployment
- Id: Guid (Primary Key)
- KeycloakUserId: string (Required, unique, maps to remote IdP user id)
- Name: string (Required, max 130 chars)
- Email: string (Required, max 200 chars, unique)
- DateOfBirth: DateTime? (Optional)
- CreatedAt: DateTime (User creation timestamp)
- LastLoginAt: DateTime? (Last login timestamp)
Note on Database: The project uses EF Core's code-first approach. Database schema is created automatically on application startup based on entity configurations in Infrastructure/Persistence/Configurations/.
All endpoints require authentication via JWT Bearer token obtained from Keycloak.
Note: User creation is managed through Keycloak login. Users are automatically provisioned in the local database upon first login (JIT provisioning).
- .NET 8.0 SDK
- JetBrains Rider (recommended) or Visual Studio or Visual Studio Code
- Docker Desktop (required for Keycloak setup)
This project uses Keycloak as the identity provider (IdP) with OAuth2/OIDC for authentication.
- Keycloak as Single Source of Truth: User accounts are managed in Keycloak
- JWT Bearer Authentication: API validates tokens issued by Keycloak
- JIT Provisioning: Users are automatically created in local database on first login
- Swagger OAuth2 Integration: Test authenticated endpoints directly from Swagger UI
Quick Start - Automated Setup:
# 1. Copy environment template
cp .env.example .env
# 2. Start infrastructure
docker-compose up -d postgres keycloak
# 3. Run automated Keycloak setup
cd Aristotle.DevTools
dotnet run -- keycloak setup
# 4. Copy the generated client secret to .env
# KEYCLOAK_CLIENT_SECRET=<generated-secret>This automated setup creates:
- Realm:
userservice - Client:
userservice-api(with PKCE enabled) - Roles: Admins, Managers, Users
- Groups: admin-group, manager-group, user-group
- Test users: admin/admin123, manager/manager123, user/user123
- Protocol mappers for roles and groups claims
Test the setup:
dotnet run -- keycloak testSee DevTools README for more details.
Runs infrastructure services (Keycloak + PostgreSQL):
cp .env.example .env
docker compose up -dAccess:
- Keycloak: http://localhost:8080
- PostgreSQL: localhost:5432
Note: The UserService container configuration exists in docker-compose.yml but is currently commented out. For local development, use Option 2 below.
Run API locally while using Keycloak from Docker:
docker compose up -d keycloak
cd USR/UserService
dotnet runAccess:
- API: http://localhost:5000
- Swagger: http://localhost:5000/swagger
- Open Swagger UI
- Click Authorize button
- Complete OAuth2 login flow with Keycloak
- Make requests to protected endpoints
The application will automatically open Swagger UI in your default browser when running in development mode.
# Run all tests
dotnet test
# Run tests with coverage
dotnet test --collect:"XPlat Code Coverage"
# Run specific test project
dotnet test USR/UserServiceTests/UserService.UnitTests.csprojThe project aims to maintain a code coverage of at least 80% to ensure reliability and maintainability. We use Coverlet for measuring code coverage and SonarCloud for visualization.
Current Status: ~45-50% coverage with 104 unit tests (all passing ✅)
To run tests with coverage and generate a coverage report:
# Run tests with coverage
dotnet test --collect:"XPlat Code Coverage" --results-directory:"./TestResults"
# Generate HTML coverage report
dotnet tool install -g dotnet-reportgenerator-globaltool
reportgenerator -reports:"./TestResults/**/coverage.cobertura.xml" \
-targetdir:"./TestResults/Report" \
-reporttypes:"Html;TextSummary"
# View the report
open ./TestResults/Report/index.html # macOS/Linux
start ./TestResults/Report/index.html # WindowsThe coverage report helps identify areas that need additional testing to meet our 80% coverage target.
The application supports hot reload with dotnet watch which provides:
- Automatic recompilation when you save code changes
- Live reload without manual restart
- Real-time feedback for development
Tip: You'll see hot reload messages in the terminal when files are changed and recompiled.
- Make code changes in your IDE
- Save the file (
Ctrl+S) - Watch the terminal for hot reload confirmation (if using
dotnet watch) - Test changes immediately in Swagger UI
- Create unit tests
- Run tests to make sure everything works
- Repeat!
The project includes unit tests covering:
- Controller endpoints with various scenarios
- Service layer business logic
- Domain entity validation
- Repository data access operations
- Exception handling
- Builder pattern for test data
Test frameworks used:
- xUnit v3 for test execution
- Moq for mocking dependencies
- Bogus for generating fake test data
The project includes API testing using Bruno, a CLI tool for testing APIs. The test collection is located in the bruno/UserService API/ directory. To execute the tests,
follow these steps:
-
Install Bruno CLI:
npm install -g @usebruno/cli
-
Run the Tests:
bruno run "bruno/UserService API" -
View Reports:
- Test results will be generated in the specified output directory if configured.
Bruno is also integrated into the CI/CD pipeline to ensure API functionality during automated builds. To understand more about this outstanding tool, visit the Bruno Documentation.
You can also download the Bruno extension for VS Code or JetBrains IDEs. or even download the Bruno Desktop App.
This is an educational project, but contributions are welcome! Areas for improvement include:
- Fix .NET compiler warnings
- Address SonarCloud security hotspots
- Expand integration test coverage
- Implement additional validators
- Improve error handling
- Add more comprehensive logging
- Increase unit test coverage (target: 80%)
Port Issues: If default ports are in use, modify the URLs in Properties/launchSettings.json
Build Issues: Run dotnet clean followed by dotnet restore and dotnet build
This project serves as a learning exercise comparing C#/.NET development patterns with Java/Spring Boot, focusing on Clean Architecture principles and modern development practices.