Some years back, I used to maintain a SaaS application built on ASP.NET WebForms. Many organizations are aiming to migrate existing applications built on the ASP.NET Framework to the amazing .NET Core.
TinySaas culminated from my work in migrating an ASP.NET legacy application to ASP.NET Core.
Why TinySaas?
There abound on the internet several frameworks that aim to allow developers to build multitenant applications using the .NET Core Framework, but the keyword (Framework).
TinySaas is a library that aims to add multitenancy support to new and existing ASP.NET Core applications without forcing the adoption of a new framework.
The credit for this library goes to Gunnar and Michael, two great authors whose several blog articles on this topic served as the foundation for this simple library.
Getting Started
Multitenancy support should not require a rewrite nor massive changes. With TinyTenant, you can now add multitenancy support to both new and existing projects in simple steps.
- Add
CodEaisy.TinySaas.AspNetCore to your application via Nuget or the .NET CLI
dotnet add package CodEaisy.TinySaas.AspNetCore --version 1.0.0
In Startup.cs, add the following inside the ConfigureServices method.
public void ConfigureServices(IServiceCollection services)
{
services.AddMultiTenancy<Tenant, TenantStore<Tenant>, TenantResolutionStrategy>();
services.AddMultiTenancy<TenantStore<TinyTenant>, TenantResolutionStrategy>();
}
Then, add the following in the Configure method.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMultitenancy<Tenant, MissingTenantHandler, MissingTenantOptions>(missingTenantOptions);
app.UseMultitenancy<Tenant, MissingTenantHandler>();
app.UseMultitenancy<TMissingTenantHandler>()
}
In Program.cs, add the following in the CreateHostBuilder method.
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.ConfigureMultiTenancy<TenantStartup, Tenant>();
.ConfigureMultiTenancy<Tenant>(ClassName.StaticMethodName);
NOTE:
Tenant must implement CodEaisy.TinySaas.Interface ITenant.
TenantStore must implement CodEaisy.TinySaas.Interface.ITenantStore.
TenantResolutionStrategy must implement CodEaisy.TinySaas.Interface.ITenantResolutionStrategy respectively.
TenantStartup must implement IMultiTenantStartup
ClassName.StaticMethodName must be of type System.Action<TTenant, Autofac.ContainerBuilder> where TTenant implements ITenant
Use Cases
TinySaas supports the most common use cases for multitenant development, and below are some examples.
Global Services
Global Services are services that do not have a core dependency on the tenant information, and they can be registered just the same way you have been used to in .NET Core, in the Startup.ConfigureServices method.
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IGlobalSingletonService, GlobalSingletonService>();
services.AddScoped<IGlobalScopedService, GlobalScopedService>();
services.AddTransient<IGlobalTransientService, GlobalTransientService>();
services.AddControllers();
}
Tenant Services
Tenant Services are services that have core dependencies on the tenant information. TinySaas allows you to register these services like every other .NET Core service but in a tenant aware location.
Usually, tenant services will be registered either in the ConfigureServices method of your TenantStartup class or in the delegate passed to the IHostBuilder.ConfigureMultiTenancy in the Program.cs file.
public void ConfigureTenantServices(Tenant tenant, ContainerBuilder container)
{
container.RegisterType<TenantSingletonService>().SingleInstance();
container.RegisterType<TenantScopedService>().InstancePerRequest();
container.RegisterType<TenantTransient>().InstancePerDependency();
#region .NET Core DI way
var services = new ServiceCollection();
services.AddSingleton<ITenantSingletonService, TenantSingletonService>();
services.AddScoped<ITenantScopedService, TenantScopedService>();
services.AddTransient<ITenantTransientService, TenantTransientService>();
container.Populate(services);
#endregion
}
Databases
Multitenancy is not complete without databases, and TinySaas has an answer to all your needs.
Shared Database (Single Schema and Schema per Tenant)
Register your DbContext the old way and inject IHttpContextAccessor via your DbContext constructor.
public void ConfigureService(IServiceCollection services)
{
services.AddDbContext<AppDbContext>(...);
}
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options, IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
}
`
Database Per Tenant
Simply move the DbContext registration to the multitenant service configuration method.
public void ConfigureTenantServices(Tenant tenant, ContainerBuilder container)
{
var services = new ServiceCollection();
services.AddDbContext<AppDbContext>(tenant.ConnectionString);
container.Populate(services);
}
Other Concerns
Options can also be registered the same way as discussed for services and databases.
You can check out the source repo for TinySaas on Github, and give feedback via the issues tab.
Thank you for reading 🍾.