Scenario: EF Core Database-Per-Tenant Isolation¶
Goal¶
Document a sample that uses database-per-tenant isolation with EF Core helpers, per-tenant migrations, and strict SaveChanges enforcement.
Sample name and location¶
- Solution:
CleanArchitecture.Extensions.Samples.Multitenancy.EfCoreDatabasePerTenant - Path:
samples/CleanArchitecture.Extensions.Samples.Multitenancy.EfCoreDatabasePerTenant
Modules used¶
- Multitenancy core
- Multitenancy.AspNetCore
- Multitenancy.EFCore
Prerequisites¶
- Base Web API solution using SQLite with the Clean Architecture template.
- Numbered step comments and matching README entries for every change.
Steps¶
- Add references to
CleanArchitecture.Extensions.Multitenancy,CleanArchitecture.Extensions.Multitenancy.AspNetCore, andCleanArchitecture.Extensions.Multitenancy.EFCore; include them in the sample solution. - Configure
EfCoreMultitenancyOptionstoDatabasePerTenant, set the tenant ID property name, and mark global entities (Identity tables, etc.) as exclusions. - Implement
ITenantConnectionResolvermapping each tenant to a SQLite file underApp_Data/{tenantId}.db, allowing premium/regional tenants to pick dedicated databases if needed. - Replace the default DbContext registration with
ITenantDbContextFactory<ApplicationDbContext>using theTenantDbContextbase class plusTenantSaveChangesInterceptorand the tenant-aware model customizer. - Wire
TenantMigrationRunnerto run migrations per tenant; include a CLI/hosted command that iterates the tenant catalog and migrates active tenants. - Ensure the web pipeline resolves tenants before EF Core usage and keep
TenantEnforcementBehaviorenabled so data access cannot occur without tenant context. - Add tests verifying per-tenant database files are created, cross-tenant queries are blocked, and global entities bypass filters when configured.
- Document operational guidance: backup/restore per tenant, handling connection string rotation, and cleaning up databases on tenant deletion.
Validation¶
- Each tenant writes to its own SQLite file; queries do not cross boundaries.
- SaveChanges fails when tenant context is missing or mismatched.
- Migration runner reports per-tenant status and supports reruns without data loss.