A production-ready, enterprise-grade .NET 8 Web API template following Clean Architecture principles and industry best practices. This template is designed to be reusable as a foundation for multiple projects and can easily integrate with modern frontend frameworks.
This template implements Clean Architecture with clear separation of concerns across four distinct layers:
src/
├── CleanArchitecture.API/ # Presentation Layer
│ ├── Controllers/ # API Controllers
│ ├── Middleware/ # Custom middleware
│ └── Program.cs # Application entry point
│
├── CleanArchitecture.Application/ # Business Logic Layer
│ ├── Common/ # Shared application logic
│ │ ├── Behaviours/ # MediatR pipeline behaviours
│ │ ├── Interfaces/ # Application interfaces
│ │ └── Models/ # DTOs and response models
│ └── Features/ # Feature-based organization
│ └── Products/ # Example: Product feature
│ ├── Commands/ # CQRS Commands
│ ├── Queries/ # CQRS Queries
│ └── DTOs/ # Data Transfer Objects
│
├── CleanArchitecture.Domain/ # Domain Layer
│ ├── Common/ # Base entities and interfaces
│ └── Entities/ # Domain entities
│
└── CleanArchitecture.Infrastructure/ # Infrastructure Layer
├── Persistence/ # Database context and repositories
└── Services/ # External services implementation
- Clean Architecture with strict layer separation
- CQRS Pattern using MediatR
- Repository Pattern for data access
- Unit of Work for transaction management
- Dependency Injection throughout
- SOLID Principles applied consistently
- Global Exception Handling - Custom middleware with structured error responses
- Request Logging - Comprehensive request/response logging with Serilog
- JWT Authentication - Token-based authentication with role support
- Role-Based Authorization - Fine-grained access control
- API Response Wrapper - Consistent response format across all endpoints
- Pagination, Filtering & Sorting - Generic implementation for all list endpoints
- FluentValidation - Automatic request validation
- AutoMapper - Object-to-object mapping
- Swagger/OpenAPI - Interactive API documentation with JWT support
- Rate Limiting - Built-in request throttling
- Health Checks - Database and application health monitoring
- CORS - Configurable cross-origin resource sharing
- In-Memory Caching - Ready to extend to Redis
- Entity Framework Core 8 with PostgreSQL
- Supabase Integration - Ready for cloud deployment
- Generic Repository Pattern - Reusable data access
- Soft Delete Support - Entities marked as deleted instead of removed
- Audit Fields - CreatedAt, UpdatedAt, CreatedBy, UpdatedBy
- Feature-Based Organization - Easy to navigate and extend
- Example CRUD Module - Complete Products example
- Strongly Typed Configuration - Type-safe settings
- Environment-Based Configs - Development and production settings
- .NET 8 SDK
- PostgreSQL (or Supabase account)
- IDE (Visual Studio 2022, VS Code, or Rider)
-
Clone the repository
git clone <repository-url> cd CleanArchitecture
-
Configure environment variables
Copy
.env.exampleto.envand update with your values:cp .env.example .env
Required variables:
SUPABASE_URL=your_supabase_url SUPABASE_SERVICE_ROLE_KEY=your_service_role_key JWT_SECRET=your_jwt_secret_key -
Restore dependencies
dotnet restore
-
Update database
cd src/CleanArchitecture.API dotnet ef database update -
Run the application
dotnet run
The API will be available at https://localhost:5001 and Swagger UI at https://localhost:5001
cd src/CleanArchitecture.API
dotnet ef migrations add MigrationName --project ../CleanArchitecture.Infrastructuredotnet ef database updatedotnet ef migrations remove --project ../CleanArchitecture.InfrastructureOnce running, access the Swagger UI at the root URL to explore and test all endpoints.
-
Login to get JWT token
POST /api/auth/login { "username": "admin", "password": "admin123" }Default users:
- Admin:
admin/admin123 - User:
user/user123
- Admin:
-
Use the token in Swagger
- Click "Authorize" button
- Enter:
Bearer {your-token} - Click "Authorize"
GET /api/products- Get paginated productsGET /api/products/{id}- Get product by IDPOST /api/products- Create product (Admin only)PUT /api/products/{id}- Update product (Admin only)DELETE /api/products/{id}- Delete product (Admin only)
Query parameters for listing:
pageNumber- Page number (default: 1)pageSize- Items per page (default: 10, max: 100)sortBy- Sort field (name, price, createdAt)sortDescending- Sort direction (default: false)searchTerm- Search in name and descriptioncategory- Filter by categoryisActive- Filter by active status
// src/CleanArchitecture.Domain/Entities/YourEntity.cs
public class YourEntity : BaseEntity
{
public string Name { get; set; } = string.Empty;
// Add your properties
}// src/CleanArchitecture.Infrastructure/Persistence/ApplicationDbContext.cs
public DbSet<YourEntity> YourEntities => Set<YourEntity>();// src/CleanArchitecture.Application/Features/YourFeature/DTOs/YourEntityDto.cs
public class YourEntityDto
{
public Guid Id { get; set; }
public string Name { get; set; } = string.Empty;
}// src/CleanArchitecture.Application/Features/YourFeature/Commands/CreateYourEntity/CreateYourEntityCommand.cs
public class CreateYourEntityCommand : IRequest<YourEntityDto>
{
public string Name { get; set; } = string.Empty;
}// src/CleanArchitecture.Application/Features/YourFeature/Commands/CreateYourEntity/CreateYourEntityCommandHandler.cs
public class CreateYourEntityCommandHandler : IRequestHandler<CreateYourEntityCommand, YourEntityDto>
{
// Implement handler logic
}// src/CleanArchitecture.Application/Features/YourFeature/Commands/CreateYourEntity/CreateYourEntityCommandValidator.cs
public class CreateYourEntityCommandValidator : AbstractValidator<CreateYourEntityCommand>
{
public CreateYourEntityCommandValidator()
{
RuleFor(x => x.Name).NotEmpty().MaximumLength(200);
}
}// src/CleanArchitecture.API/Controllers/YourEntitiesController.cs
[ApiController]
[Route("api/[controller]")]
public class YourEntitiesController : ControllerBase
{
private readonly IMediator _mediator;
public YourEntitiesController(IMediator mediator)
{
_mediator = mediator;
}
[HttpPost]
public async Task<ActionResult<ApiResponse<YourEntityDto>>> Create([FromBody] CreateYourEntityCommand command)
{
var result = await _mediator.Send(command);
return Ok(ApiResponse<YourEntityDto>.SuccessResponse(result));
}
}// src/CleanArchitecture.Application/Features/YourFeature/MappingProfile.cs
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<YourEntity, YourEntityDto>();
}
}dotnet ef migrations add AddYourEntity --project src/CleanArchitecture.Infrastructure
dotnet ef database updateConfigure application settings in src/CleanArchitecture.API/appsettings.json:
{
"Serilog": {
"MinimumLevel": {
"Default": "Information"
}
},
"AllowedHosts": "*"
}The following environment variables are supported:
SUPABASE_URL- Supabase project URLSUPABASE_SERVICE_ROLE_KEY- Supabase service role keyJWT_SECRET- Secret key for JWT token generationJWT_ISSUER- JWT token issuerJWT_AUDIENCE- JWT token audienceJWT_EXPIRATION_MINUTES- Token expiration time in minutesASPNETCORE_ENVIRONMENT- Environment (Development/Production)
This API is designed to work seamlessly with modern frontend frameworks:
const API_URL = 'https://your-api-url.com';
// Login
const login = async (username: string, password: string) => {
const response = await fetch(`${API_URL}/api/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
});
const data = await response.json();
return data.data.token;
};
// Get products with pagination
const getProducts = async (page: number, pageSize: number) => {
const response = await fetch(
`${API_URL}/api/products?pageNumber=${page}&pageSize=${pageSize}`,
{
headers: {
'Authorization': `Bearer ${token}`
}
}
);
const data = await response.json();
return data.data;
};import { HttpClient, HttpHeaders } from '@angular/common/http';
@Injectable()
export class ApiService {
private apiUrl = 'https://your-api-url.com';
constructor(private http: HttpClient) {}
login(username: string, password: string) {
return this.http.post(`${this.apiUrl}/api/auth/login`,
{ username, password });
}
getProducts(page: number, pageSize: number) {
const headers = new HttpHeaders({
'Authorization': `Bearer ${this.token}`
});
return this.http.get(`${this.apiUrl}/api/products`, {
headers,
params: { pageNumber: page, pageSize }
});
}
}This template implements several security measures:
- JWT Authentication - Secure token-based authentication
- Role-Based Authorization - Granular access control
- Input Validation - FluentValidation on all inputs
- SQL Injection Prevention - Parameterized queries via EF Core
- CORS Configuration - Controlled cross-origin access
- Rate Limiting - Protection against abuse
- Secure Password Handling - Never log or expose credentials
- HTTPS Redirection - Force secure connections
Before deploying to production:
- Change default JWT secret
- Update authentication to use real user database
- Configure CORS for specific origins only
- Set appropriate rate limits
- Enable HTTPS
- Configure logging to external service
- Set up health check monitoring
- Review and adjust cache expiration times
- Disable Swagger in production (or protect it)
- Set up proper database backups
- Run the application
- Navigate to the root URL
- Use the interactive Swagger UI to test endpoints
Import the OpenAPI spec from /swagger/v1/swagger.json
- API → Application, Infrastructure
- Application → Domain
- Infrastructure → Application, Domain
- Domain → None (no dependencies)
- Commands:
{Verb}{Entity}Command(e.g.,CreateProductCommand) - Queries:
Get{Entity}Query(e.g.,GetProductByIdQuery) - DTOs:
{Entity}Dto(e.g.,ProductDto) - Validators:
{Command/Query}Validator - Handlers:
{Command/Query}Handler
- Use Caching - Cache frequently accessed data
- Optimize Queries - Use pagination for large datasets
- Async/Await - All database operations are async
- Connection Pooling - EF Core handles this automatically
- Index Database - Add indexes for frequently queried columns
- Verify Supabase credentials in
.env - Check network connectivity
- Ensure database is accessible
- Delete existing migrations and recreate
- Verify connection string
- Check entity configurations
- Verify JWT secret is configured
- Check token expiration time
- Ensure proper Bearer token format
When contributing to this template:
- Follow existing code style and patterns
- Add tests for new features
- Update documentation
- Create feature branches
- Submit pull requests with clear descriptions
This template is provided as-is for use in your projects.
For issues and questions:
- Check existing documentation
- Review example implementations
- Consult the Clean Architecture principles
Future enhancements:
- Unit and integration tests
- Docker support
- CI/CD pipeline examples
- Message queue integration
- Redis caching
- Email service
- File upload/storage
- Audit logging
- API versioning
- GraphQL endpoint option
Built with ❤️ using .NET 8 and Clean Architecture principles