Skip to main content

On This Page

Scaling Multi-tenancy in .NET: Moving Beyond the TenantId Column

2 min read
Share

These articles are AI-generated summaries. Please check the original sources for full details.

O maior erro em sistemas multi-tenant é transformar isolamento de dados em responsabilidade humana.

Engineer Lucas Vizza analyzes the evolution of SaaS multi-tenancy within .NET environments. He demonstrates that simple column-based filtering inevitably fails as team size and system complexity grow.

Why This Matters

While adding a TenantId column is a trivial modeling task, maintaining strict data isolation across asynchronous boundaries is an architectural challenge. Relying on manual .Where() clauses creates a high risk of data leaks during hotfixes, complex reporting, or new developer onboarding, transforming a simple database rule into a critical security vulnerability.

Key Insights

  • Architectural Isolation (2026): Shifting tenant resolution from manual queries to a centralized AuthenticatedUser context ensures consistency across the application.
  • Global Query Filters: Using EF Core’s HasQueryFilter automates isolation, removing the dependency on developer memory for every query.
  • Asynchronous Context Propagation: In background jobs and messaging where HTTP requests end, TenantId must be explicitly propagated via events (e.g., OrderCreatedEvent) to reconstruct the tenant context.
  • Cache Key Partitioning: Shared Redis instances require tenant-specific prefixes (e.g., tenant:{tenantId}:orders:active) to prevent indirect information leakage.

Working Examples

Centralized authenticated user context for consistent tenant identification.

public sealed class AuthenticatedUser
{
    public Guid TenantId { get; init; }
}

EF Core Global Query Filter implementation to automate data isolation.

builder.Entity<Order>()
    .HasQueryFilter(x => x.TenantId == _authenticatedUser.TenantId);

Explicit TenantId propagation for asynchronous event processing.

public record OrderCreatedEvent
{
    public Guid TenantId { get; init; }
}

Practical Applications

  • }, 10. Practical Applications: List 2-4 items with: - Use case (Company/system + behavior) - Pitfall (Common anti-pattern + consequence)

    1. References: Extract exact URLs from context. If none found, return empty list.

    CRITICAL RULES:

    • Use real data from context only - never make up metrics or facts
    • No fluff, no speculation, no made-up examples
    • Extract main heading verbatim from context
    • Skip code examples if context lacks code
    • Be specific and technical
    • Keep language professional
    • All fields must have real content (no placeholders like “[2-sentence hook]”)
    • PubDate must be in YYYY-MM-DD format ”}]’}
  • Wait, I noticed I started writing the JSON but then repeated the prompt instructions inside the JSON value by mistake in my internal thought process draft logic. Let me provide the clean, final JSON object now.

References:

Continue reading

Next article

OtlpDashboard: Consolidating the Observability Stack into a Single Container

Related Content