Designing Multi‑Tenant SaaS Applications with .NET 8, EF Core, and Azure SQL Elastic Pools

Mahmut Sarıkaya 4 dk okuma 20 Görüntülenme 0
Designing Multi‑Tenant SaaS Applications with .NET 8, EF Core, and Azure SQL Elastic Pools

Why Multi‑Tenant Architecture Matters for Modern SaaS

Imagine a startup that launches a subscription‑based analytics platform and needs to support 10,000 customers within the first six months. A single‑tenant deployment would require 10,000 separate instances, exploding operational cost and maintenance overhead. Multi‑tenant design consolidates those customers into a shared codebase and database layer while preserving data isolation, enabling predictable scaling and lower per‑customer price.

Choosing .NET 8 as the Foundation

.NET 8, released in November 2023, introduces native support for minimal APIs, improved AOT compilation, and built‑in diagnostics that are ideal for high‑density SaaS workloads. The new Microsoft.AspNetCore.Http.HttpContext extensions let you inject tenant identifiers early in the request pipeline, reducing boilerplate. For example, a middleware that reads a sub‑domain and stores it in HttpContext.Items can be written in less than 30 lines.

public class TenantResolutionMiddleware
{    private readonly RequestDelegate _next;
    public TenantResolutionMiddleware(RequestDelegate next) => _next = next;
    public async Task InvokeAsync(HttpContext context)
    {        var host = context.Request.Host.Host;
        var tenantId = host.Split('.').FirstOrDefault(); // assumes tenant.myapp.com
        if (!string.IsNullOrEmpty(tenantId))
        {            context.Items["TenantId"] = tenantId;
        }
        await _next(context);
    }
}

Register the middleware in Program.cs with app.UseMiddleware<TenantResolutionMiddleware>(); and every downstream service can retrieve the tenant ID without repeating parsing logic.

Database Strategy: Azure SQL Elastic Pools

Azure SQL Elastic Pools allow you to host dozens of databases—each representing a tenant—while sharing a common set of compute resources. The pool automatically balances DTU or vCore consumption across active databases, which is perfect for SaaS where some tenants are idle and others spike during reporting periods. Microsoft reports up to 80 % cost reduction compared to provisioning individual single‑tenant databases at peak capacity.

When you create a pool, you define a maximum eDTU (elastic DTU) and a per‑database cap. For a SaaS with 2,000 tenants, a pool of 5,000 eDTU and a per‑database limit of 25 eDTU often suffices, letting the most demanding tenant use up to 25 eDTU while the pool absorbs occasional bursts.

EF Core Model Design for Tenant Isolation

EF Core 8 adds HasQueryFilter support for global filters, which you can tie to the tenant ID stored in HttpContext. Define a base entity that includes TenantId and apply the filter in OnModelCreating:

public abstract class TenantEntity
{    public string TenantId { get; set; }
}
public class Order : TenantEntity
{    public int Id { get; set; }
    public decimal Amount { get; set; }
}
public class AppDbContext : DbContext
{    private readonly IHttpContextAccessor _httpAccessor;
    public AppDbContext(DbContextOptions<AppDbContext> options, IHttpContextAccessor httpAccessor)
        : base(options) => _httpAccessor = httpAccessor;
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {        var tenantId = _httpAccessor.HttpContext?.Items["TenantId"] as string;
        modelBuilder.Entity<Order>().HasQueryFilter(o => o.TenantId == tenantId);
    }
}

This approach guarantees that every LINQ query automatically includes the tenant predicate, eliminating accidental cross‑tenant data leaks. For write operations, set TenantId in SaveChangesAsync overrides.

Connection Management and Elastic Pool Scaling

Each tenant’s connection string points to its dedicated database within the pool. Store the mapping in a lightweight configuration service (Azure App Configuration or a Redis cache). When a new tenant signs up, automate database provisioning with Azure CLI:

az sql db create \
  --resource-group MySaaS-rg \
  --server mysaas-sql \
  --name tenant_12345 \
  --elastic-pool MySaaSPool \
  --collation SQL_Latin1_General_CP1_CI_AS

Because the pool already allocates compute, creating a new database takes seconds and costs only storage. Monitor pool utilization via Azure Monitor; set alerts at 80 % eDTU usage to trigger automatic scaling of the pool’s eDTU quota.

Performance Tips and Real‑World Numbers

A case study from a European fintech SaaS showed that moving from 200 single‑tenant Azure SQL databases to a 3,000‑eDTU elastic pool cut monthly DB costs from $12,000 to $4,500 while maintaining sub‑200 ms query latency for 95 % of requests. Key tactics included:

  • Enabling Read‑Committed Snapshot Isolation to reduce lock contention.
  • Using compiled queries in EF Core for frequent lookup patterns (e.g., dbContext.Orders.FirstOrDefaultAsync(o => o.Id == id)).
  • Implementing a tenant‑specific connection pool via Microsoft.Data.SqlClient connection string pooling.

Testing Multi‑Tenant Logic Locally

During development, you can simulate the pool with a single local Azure SQL instance and create separate databases named tenant_dev_1, tenant_dev_2, etc. Use Docker to spin up mcr.microsoft.com/mssql/server:2022-latest and connect with Server=localhost,1433;User Id=sa;Password=YourStrong!Pass;. The same EF Core filter logic works unchanged, giving confidence before pushing to Azure.

Conclusion

Designing a multi‑tenant SaaS on .NET 8, EF Core, and Azure SQL Elastic Pools blends modern .NET performance with Azure’s cost‑effective scaling. By centralizing tenant resolution in middleware, applying global query filters, and leveraging elastic pool elasticity, you can support thousands of customers while keeping operational overhead predictable. The practical steps—middleware, EF Core configuration, automated database creation, and monitoring—translate directly into faster time‑to‑market and lower TCO.

Sources

Microsoft Docs – Azure SQL Elastic Pools; Microsoft Docs – EF Core Global Query Filters; Azure Architecture Center – Multi‑tenant SaaS design patterns

Author: Mahmut Sarıkaya — sarikayadev.com

Etiketler: #.NET 8 #multi‑tenant #SaaS architecture #EF Core #Azure SQL Elastic Pools
Paylaş:
M

Yazar

Mahmut Sarıkaya

yazılım Geliştirici

Yorumlar

Henüz yorum yok. İlk yorumu siz yapın!

Yorum Bırakın

9 + 3 =