A robust multi-tenant ASP.NET Core application using database-per-tenant architecture with enhanced performance, security, and monitoring features.
This application implements a Database-per-Tenant multi-tenancy pattern where:
- Each tenant has their own dedicated database
- Tenant resolution is based on HTTP request host/domain
- Centralized tenant metadata management
- Enhanced caching and performance optimizations
- β Database-per-tenant isolation
- β Domain-based tenant resolution
- β Dynamic database context creation
- β Tenant metadata management
- β In-memory caching for tenant resolution
- β Database connection pooling
- β Async/await throughout
- β Connection health testing
- β Application health checks
- β Per-tenant database health monitoring
- β Structured logging with Serilog
- β Performance metrics
- β Connection string masking in logs
- β Input validation
- β Secure error handling
- β CORS configuration
- β Swagger/OpenAPI documentation
- β Docker support
- β Development environment setup
- β Comprehensive error messages
- Framework: ASP.NET Core 7.0
- Database: MySQL 8.0+ / 9.0+
- ORM: Entity Framework Core
- Logging: Serilog
- Caching: MemoryCache
- Containerization: Docker
- API Documentation: Swagger/OpenAPI
- .NET 7.0 SDK
- MySQL Server
- Docker (optional)
git clone <repository-url>
cd MultiTenantEdit appsettings.json:
{
"ConnectionStrings": {
"DefaultConnection": "server=localhost;Port=3306;user=root;password=yourpassword;database=MultiTenantDb;"
}
}dotnet restoredotnet ef database update --context ApplicationDbContextdotnet run- API Documentation:
https://localhost:7067 - Health Check:
https://localhost:7067/health - Tenant Info:
https://localhost:7067/api/MultiTenant/tenant-info
# Start all services (MySQL + API)
docker-compose up -d
# View logs
docker-compose logs -f
# Stop services
docker-compose down# Build image
docker build -t multitenant-api .
# Run container
docker run -d -p 5075:80 -p 7067:443 multitenant-api- Purpose: Store tenant metadata
- Tables:
Tenants,Roles - Connection: Configured in
appsettings.json
- Purpose: Store tenant-specific data
- Tables:
Tokens(example) - Connection: Dynamic, based on tenant configuration
The system seeds two default tenants:
- ssprintl - Domain:
localhost - infisquare - Domain:
localhost2
GET /api/MultiTenant/tenant-info # Get current tenant info
GET /api/MultiTenant/health # Tenant health checkGET /api/MultiTenant/tokens # Get all tokens
GET /api/MultiTenant/tokens/{id} # Get specific token
POST /api/MultiTenant/tokens # Create new tokenGET /health # Overall system health{
"ConnectionStrings": {
"DefaultConnection": "server=localhost;Port=3306;..."
},
"TenantSettings": {
"CacheExpirationMinutes": 30,
"ConnectionTimeoutSeconds": 120,
"DefaultMySqlVersion": "9.0.1"
},
"AllowedOrigins": ["http://localhost:3000"],
"Serilog": {
"MinimumLevel": "Information"
}
}ASPNETCORE_ENVIRONMENT=Development
ConnectionStrings__DefaultConnection="server=localhost;..."- Application health:
/health - Database connectivity for all tenants
- Tenant resolution functionality
- Console: Development environment
- File:
logs/multitenant-YYYY-MM-DD.log - Structured: JSON format with correlation IDs
- Tenant resolution performance
- Database connection health
- Request/response timing
Use different hosts in your requests:
# Test tenant 1 (ssprintl)
curl -H "Host: localhost" https://localhost:7067/api/MultiTenant/tokens
# Test tenant 2 (infisquare)
curl -H "Host: localhost2" https://localhost:7067/api/MultiTenant/tokens# Overall health
curl https://localhost:7067/health
# Tenant-specific health
curl -H "Host: localhost" https://localhost:7067/api/MultiTenant/health- Update connection strings
- Configure logging levels
- Set up SSL certificates
- Configure CORS origins
- Set up monitoring
- Database backups
- Security scanning
ASPNETCORE_ENVIRONMENT=Production
ASPNETCORE_URLS=https://+:443;http://+:80
ConnectionStrings__DefaultConnection="Production connection string"- Fork the repository
- Create feature branch:
git checkout -b feature/amazing-feature - Commit changes:
git commit -m 'Add amazing feature' - Push to branch:
git push origin feature/amazing-feature - Open Pull Request
None - all improvements are backward compatible.
- Update
appsettings.jsonwith new configuration sections - Install new NuGet packages
- Update any custom tenant resolution logic if applicable
- Connection strings are masked in logs
- Input validation on all endpoints
- Secure error handling (no internal details exposed)
- CORS properly configured
- Database connections properly disposed
This project is licensed under the MIT License - see the LICENSE file for details.
For support and questions:
- Create an issue in the repository
- Check existing documentation
- Review logs for troubleshooting
Made with β€οΈ using ASP.NET Core