Knara.MultiTenant.IsolationEnforcer
1.0.4
dotnet add package Knara.MultiTenant.IsolationEnforcer --version 1.0.4
NuGet\Install-Package Knara.MultiTenant.IsolationEnforcer -Version 1.0.4
<PackageReference Include="Knara.MultiTenant.IsolationEnforcer" Version="1.0.4" />
<PackageVersion Include="Knara.MultiTenant.IsolationEnforcer" Version="1.0.4" />
<PackageReference Include="Knara.MultiTenant.IsolationEnforcer" />
paket add Knara.MultiTenant.IsolationEnforcer --version 1.0.4
#r "nuget: Knara.MultiTenant.IsolationEnforcer, 1.0.4"
#:package Knara.MultiTenant.IsolationEnforcer@1.0.4
#addin nuget:?package=Knara.MultiTenant.IsolationEnforcer&version=1.0.4
#tool nuget:?package=Knara.MultiTenant.IsolationEnforcer&version=1.0.4
Multi-Tenant Data Isolation Enforcer
Multi-tenant data isolation for .NET applications with compile-time enforcement.
Problem and Solution
Problem: Tenant data leaks are among the most common and costly mistakes in multi-tenant applications.
Solution: This library prevents tenant isolation errors through compile-time analysis via Roslyn analyzers and runtime safeguards.
Before (Unsafe)
public async Task<List<Order>> GetOrders()
{
return await _context.Orders.ToListAsync(); // Returns ALL tenants' data
}
After (Protected)
public async Task<List<Order>> GetOrders()
{
return await _orderRepository.GetAllAsync(); // Automatically tenant-filtered
}
// Attempting direct DbSet access produces:
// Error MTI001: Use ITenantIsolatedRepository<Order> instead of direct DbSet access
Requirements
- .NET 8.0 or later
Installation
NuGet Packages
dotnet add package Knara.MultiTenant.IsolationEnforcer
dotnet add package Knara.MultiTenant.IsolationEnforcer.Analyzers
<ItemGroup>
<PackageReference Include="Knara.MultiTenant.IsolationEnforcer" Version="1.0.0" />
<PackageReference Include="Knara.MultiTenant.IsolationEnforcer.Analyzers" Version="1.0.0"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
Clone and Build
git clone https://github.com/tasriyan/Knara.MultiTenant.IsolationEnforcer
cd Knara.MultiTenant.IsolationEnforcer
dotnet build
Quick Start
1. Configure Services
services.AddMultiTenantIsolation()
.WithInMemoryTenantCache()
.WithTenantsStore<YourTenantStore>()
.WithSubdomainResolutionStrategy(options =>
{
options.ExcludedSubdomains = new[] { "www", "api", "admin" };
});
app.UseAuthentication();
app.UseMultiTenantIsolation();
2. Choose Isolation Approach
Option A: TenantIsolatedDbContext (Automatic Filtering)
public class YourDbContext : TenantIsolatedDbContext
{
public YourDbContext(DbContextOptions<YourDbContext> options,
ITenantContextAccessor tenantAccessor,
ILogger<YourDbContext> logger)
: base(options, tenantAccessor, logger) { }
}
// Use DbContext directly
public async Task<List<Order>> GetOrders()
{
return await _context.Orders.ToListAsync(); // Automatically filtered
}
Option B: TenantIsolatedRepository (Manual Filtering)
public class OrderService
{
private readonly TenantIsolatedRepository<Order, YourDbContext> _orderRepo;
public async Task<List<Order>> GetOrders()
{
return await _orderRepo.GetAllAsync(); // Manually filtered
}
}
3. Mark Entities
public class Order : ITenantIsolated
{
public Guid Id { get; set; }
public Guid TenantId { get; set; } // Auto-assigned
public string CustomerName { get; set; }
}
Documentation
- Configuration Guide - Setup and configuration options
- Features Overview - Library capabilities
- Tenant Resolvers - Tenant detection strategies
- Demo Project - Working example showing all library features
Key Features
Compile-Time Enforcement
- MTI001: Direct DbSet access prohibited
- MTI002: Cross-tenant authorization required
- MTI003: Filter bypass warnings
- MTI005: System context authorization required
Runtime Protection
- Global query filters:
WHERE TenantId = @currentTenant - SaveChanges validation prevents cross-tenant modifications
- Automatic TenantId assignment
- Exception throwing on violations
Mandatory Monitoring
- Query performance tracking
- Violation logging
- Cross-tenant operation auditing
Cross-Tenant Operations
For legitimate administrative operations:
[AllowCrossTenantAccess("Admin reporting", "SystemAdmin")]
public async Task<AdminReport> GetGlobalReport()
{
return await _crossTenantManager.ExecuteCrossTenantOperationAsync(
async () => await GenerateReport(),
"Global admin reporting"
);
}
Tenant Resolution
Built-in strategies:
.WithSubdomainResolutionStrategy() // tenant1.yourapp.com
.WithJwtResolutionStrategy() // JWT claims
.WithHeaderResolutionStrategy() // X-Tenant-ID header
.WithPathResolutionStrategy() // /tenant1/api/users
Comparison to Other Libraries
Compared to libraries like Finbuckle.MultiTenant, this library is more restrictive:
- Compile-time enforcement via Roslyn analyzers
- Mandatory performance monitoring
- Opinionated design with fewer configuration options
This library assumes developers will make mistakes and attempts to prevent them at compile time.
Migration from Existing Applications
- Install package and configure services
- Choose TenantIsolatedDbContext or TenantIsolatedRepository
- Add ITenantIsolated interface to entities
- Replace direct DbContext usage with repositories (Option B only)
- Fix compilation errors guided by analyzers
- Add database migration for TenantId columns
When to Use
Good fit:
- Teams frequently making tenant isolation mistakes
- Preference for compile-time safety over flexibility
- New multi-tenant applications
- Opinionated tools with fewer configuration options
Not suitable:
- Need for maximum flexibility
- Complex tenant resolution requirements beyond built-in resolvers
- Large existing codebases resistant to repository pattern adoption
License
MIT License. Copyright 2025 Tatyana Asriyan
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.AspNetCore.Http.Abstractions (>= 2.3.0)
- Microsoft.EntityFrameworkCore (>= 9.0.8)
- Microsoft.Extensions.Caching.Abstractions (>= 9.0.8)
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.8)
- Microsoft.Extensions.Options (>= 9.0.8)
- System.Text.Json (>= 9.0.8)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.