Select theme:
In this post I'm going to show you how to enable multitenancy with data isolation for Blazor application in few steps. The end result will be an application that uses a separate database for every tenant. The current tenant will be determined from the application URL.
1. Create new Blazor application, add new MSSQL data-source connected to our Sample database and auto-generate pages.

2. Run the application from Radzen to generate everything needed and add the following file to application ignore list to tell Radzen to ignore it during subsequent code generation.
server\Program.cs

3. Add the following Multitenancy section in server\appsettings.json with information about tenants, their hostnames and connection strings. We specify two hostnames per tenant - one for debug mode (so you can test while developing the application) and one for production (which your users will browse).
serverappsettings.json
{
...
"ConnectionStrings": {
"SampleConnection": "Server=.;Initial Catalog=Sample-Tenant1;Persist Security Info=False;User ID=sa;Password=passw0rdMSSQL;MultipleActiveResultSets=False;Encrypt=false;TrustServerCertificate=true;Connection Timeout=30"
},
"Multitenancy": {
"Tenants": [
{
"Name": "Tenant1",
"Hostnames": [
"localhost:5001",
"tenant1.radzen-rocks.com"
],
"ConnectionString": "Server=.;Initial Catalog=Sample-Tenant1;Persist Security Info=False;User ID=sa;Password=yourpassword;MultipleActiveResultSets=False;Encrypt=false;TrustServerCertificate=true;Connection Timeout=30"
},
{
"Name": "Tenant2",
"Hostnames": [
"localhost:5002",
"tenant2.radzen-rocks.com"
],
"ConnectionString": "Server=.;Initial Catalog=Sample-Tenant2;Persist Security Info=False;User ID=sa;Password=yourpassword;MultipleActiveResultSets=False;Encrypt=false;TrustServerCertificate=true;Connection Timeout=30"
}
]
}
}
4. Add partial method Startup.OnConfigureServices to read multitenancy from server\appsettings.json and register it for dependency injection together with HttpContextAccessor.
using BlazorMultiTenant.Data;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.ObjectModel;
namespace BlazorMultiTenant
{
public partial class Startup
{
partial void OnConfigureServices(IServiceCollection services)
{
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton(Configuration.GetSection("Multitenancy").Get<Multitenancy>());
}
partial void OnConfigure(IApplicationBuilder app, IWebHostEnvironment env)
{
using (var scope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
using (var context = scope.ServiceProvider.GetService<SampleContext>())
{
var created = context.Database.EnsureCreated();
if (created)
{
var databaseCreator = (RelationalDatabaseCreator)context.Database.GetService<IDatabaseCreator>();
databaseCreator.CreateTables();
}
}
using (var context = scope.ServiceProvider.GetService<ApplicationIdentityDbContext>())
{
context.Database.Migrate();
}
}
}
}
public class Tenant
{
public string Name { get; set; }
public string[] Hostnames { get; set; }
public string ConnectionString { get; set; }
}
public class Multitenancy
{
public Collection<Tenant> Tenants { get; set; }
}
}

5. Enable default security for the application and auto-generate pages for user and role management.

6. Add server\Data\SampleContext.Custom.cs and server\Data\ApplicationIdentityDbContext.Custom.cs with the following code to read the tenants.
SampleContext.Custom.cs
public partial class SampleContext
{
private readonly HttpContext context;
private readonly Multitenancy multitenancy;
public SampleContext(DbContextOptions<SampleContext> options, ApplicationIdentityDbContext identityDbContext, IHttpContextAccessor httpContextAccessor, Multitenancy mt) : base(options)
{
context = httpContextAccessor.HttpContext;
multitenancy = mt;
}
public SampleContext(IHttpContextAccessor httpContextAccessor, Multitenancy mt, ApplicationIdentityDbContext identityDbContext)
{
context = httpContextAccessor.HttpContext;
multitenancy = mt;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (multitenancy != null && context != null)
{
var tenant = multitenancy.Tenants
.Where(t => t.Hostnames.Contains(context.Request.Host.Value)).FirstOrDefault();
if (tenant != null)
{
optionsBuilder.UseSqlServer(tenant.ConnectionString);
}
}
}
}
ApplicationIdentityDbContext.Custom.cs
public partial class ApplicationIdentityDbContext
{
private readonly HttpContext context;
private readonly Multitenancy multitenancy;
public ApplicationIdentityDbContext(DbContextOptions<ApplicationIdentityDbContext> options, IHttpContextAccessor httpContextAccessor, Multitenancy mt) : base(options)
{
context = httpContextAccessor.HttpContext;
multitenancy = mt;
}
public ApplicationIdentityDbContext(IHttpContextAccessor httpContextAccessor, Multitenancy mt)
{
context = httpContextAccessor.HttpContext;
multitenancy = mt;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (multitenancy != null && context != null)
{
var tenant = multitenancy.Tenants
.Where(t => t.Hostnames.Contains(context.Request.Host.Value)).FirstOrDefault();
if (tenant != null)
{
optionsBuilder.UseSqlServer(tenant.ConnectionString);
}
}
}
}
7. Add UseUrls() to server\Program.cs to specify the urls the web host will listen on for each tenant in debug mode. Modify the connection string in .env and appsettings.json and set default tenant to Tenant1.
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseKestrel();
webBuilder.UseUrls("https://localhost:5001", "https://localhost:5002");
webBuilder.UseStartup<Startup>();
});
}
.env
ConnectionStrings__SampleConnection="Server=.;Initial Catalog=Sample-Tenant1;Persist Security Info=False;User ID=sa;Password=passw0rdMSSQL;MultipleActiveResultSets=False;Encrypt=false;TrustServerCertificate=true;Connection Timeout=30"
8. Run the application, go to http://localhost:5001 and login using admin/admin to access Tenant1 database. You can now create roles and users for Tenant1.

9. Modify the connection string in .env and appsettings.json and set default tenant to Tenant2.
.env
ConnectionStrings__SampleConnection="Server=.;Initial Catalog=Sample-Tenant2;Persist Security Info=False;User ID=sa;Password=passw0rdMSSQL;MultipleActiveResultSets=False;Encrypt=false;TrustServerCertificate=true;Connection Timeout=30"
serverappsettings.json
{
...
"ConnectionStrings": {
"SampleConnection": "Server=.;Initial Catalog=Sample-Tenant2;Persist Security Info=False;User ID=sa;Password=passw0rdMSSQL;MultipleActiveResultSets=False;Encrypt=false;TrustServerCertificate=true;Connection Timeout=30"
},
"Multitenancy": {
"Tenants": [
{
"Name": "Tenant1",
"Hostnames": [
"localhost:5001",
"tenant1.radzen-rocks.com"
],
"ConnectionString": "Server=.;Initial Catalog=Sample-Tenant1;Persist Security Info=False;User ID=sa;Password=yourpassword;MultipleActiveResultSets=False;Encrypt=false;TrustServerCertificate=true;Connection Timeout=30"
},
{
"Name": "Tenant2",
"Hostnames": [
"localhost:5002",
"tenant2.radzen-rocks.com"
],
"ConnectionString": "Server=.;Initial Catalog=Sample-Tenant2;Persist Security Info=False;User ID=sa;Password=yourpassword;MultipleActiveResultSets=False;Encrypt=false;TrustServerCertificate=true;Connection Timeout=30"
}
]
}
}
10. Run the application, go to http://localhost:5002 and login using admin/admin to access Tenant2 database and add roles and users for Tenant2.

You have now separate security for each tenant!

Both ApplicationIdentityDbContext and SampleDataContext will retrieve runtime the tenant connection string depending on the application host:

Enjoy!
What We Shipped in 2025 (So Far)
October Update: GitHub Copilot, PivotDataGrid, and more new tools to boost your Blazor development
New: RadzenSkeleton Blazor Component
Add AI Chat to Your Blazor Apps with RadzenAIChat
We Rebuilt Our Website with Blazor – Here's Why (and How)
New App Template: Real Estate Website
Radzen Blazor Components v7.0 released!
Radzen is free to use. You can also test the premium features for 15 days.
Start FreeSelect theme: