A modular multi-tenancy framework for .NET that enables building feature-based applications with isolated services, configuration, and background workers. Organize functionality into features and modules, with runtime resolution of tenant contexts (shells) for true multi-tenant isolation.
$ dotnet add package CShellsA modular multi-tenancy framework for .NET that enables building feature-based applications with isolated services, configuration, and background workers.
CShells is the core runtime package that provides shell hosting, feature discovery, dependency injection container management, and configuration-driven multi-tenancy.
IShellContextScopeFactorydotnet add package CShells
using CShells.Features;
using Microsoft.Extensions.DependencyInjection;
[ShellFeature("Core", DisplayName = "Core Services")]
public class CoreFeature : IShellFeature
{
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<ITimeService, TimeService>();
}
}
{
"CShells": {
"Shells": [
{
"Name": "Default",
"Features": [ "Core" ]
}
]
}
}
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddCShells();
var app = builder.Build();
app.Run();
Use IShellContextScopeFactory to create scoped services within a shell's service provider:
public class ShellBackgroundWorker : BackgroundService
{
private readonly IShellHost _shellHost;
private readonly IShellContextScopeFactory _scopeFactory;
public ShellBackgroundWorker(
IShellHost shellHost,
IShellContextScopeFactory scopeFactory)
{
_shellHost = shellHost;
_scopeFactory = scopeFactory;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
foreach (var shell in _shellHost.AllShells)
{
using var scope = _scopeFactory.CreateScope(shell);
var service = scope.ServiceProvider.GetService<IMyService>();
service?.Execute();
}
await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken);
}
}
}
builder.Services.AddCShells(cshells =>
{
cshells.AddShell("Default", shell => shell
.WithFeatures("Core", "Weather")
.WithConfiguration("Theme", "Dark")
.WithConfiguration("MaxItems", "100"));
});
public class DatabaseShellSettingsProvider : IShellSettingsProvider
{
public async Task<IEnumerable<ShellSettings>> GetAllAsync()
{
// Load from database, API, etc.
return Enumerable.Empty<ShellSettings>();
}
}
builder.Services.AddCShells(cshells =>
{
cshells.WithProvider<DatabaseShellSettingsProvider>();
});