Muonroi.Tenancy.SiteProfile 1.0.0-alpha.16

This is a prerelease version of Muonroi.Tenancy.SiteProfile.
dotnet add package Muonroi.Tenancy.SiteProfile --version 1.0.0-alpha.16
                    
NuGet\Install-Package Muonroi.Tenancy.SiteProfile -Version 1.0.0-alpha.16
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Muonroi.Tenancy.SiteProfile" Version="1.0.0-alpha.16" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Muonroi.Tenancy.SiteProfile" Version="1.0.0-alpha.16" />
                    
Directory.Packages.props
<PackageReference Include="Muonroi.Tenancy.SiteProfile" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Muonroi.Tenancy.SiteProfile --version 1.0.0-alpha.16
                    
#r "nuget: Muonroi.Tenancy.SiteProfile, 1.0.0-alpha.16"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Muonroi.Tenancy.SiteProfile@1.0.0-alpha.16
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Muonroi.Tenancy.SiteProfile&version=1.0.0-alpha.16&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Muonroi.Tenancy.SiteProfile&version=1.0.0-alpha.16&prerelease
                    
Install as a Cake Tool

Muonroi.Tenancy.SiteProfile

Per-site DI registration pattern for schema-divergent multi-tenancy — wire the correct DbContext, services, and mappers for each site deployment from a single binary.

NuGet License: Apache 2.0

In multi-tenant SaaS deployments each site can carry a divergent database schema, its own EF Core DbContext subclass, and site-specific business logic. This package solves that by introducing ISiteProfile — a per-site DI registration contract — and the extension methods to activate one or many profiles at startup. A scoped ISiteProfileResolver makes the active profile available inside every HTTP request, background job, or test.

The package sits between Muonroi.Tenancy.Core (ambient TenantContext) and the higher-level Muonroi.Tenancy.SiteProfile.Web (EF Core / Dapper per-site infrastructure, middleware, hot-reload).

Installation

dotnet add package Muonroi.Tenancy.SiteProfile --prerelease

Quick Start

Single-site deployment (1 binary = 1 site)

// Program.cs
builder.Services.AddSiteProfile<Sg01Profile>(builder.Configuration);
// Sg01Profile.cs
public class Sg01Profile : ISiteProfile
{
    public string SiteId => "sg01";

    public void RegisterServices(IServiceCollection services, IConfiguration configuration)
    {
        services.AddDbContext<Sg01DbContext>(o =>
            o.UseNpgsql(configuration.GetConnectionString("Sg01")));

        services.AddKeyedScoped<IOrderService, Sg01OrderService>("sg01");
    }
}

Multi-site deployment (1 binary = N sites, reflection discovery)

// Program.cs — scans assemblies for ISiteProfile implementations
builder.Services.AddMultiSiteProfiles(
    builder.Configuration,
    siteCodeAccessor: sp => sp.GetRequiredService<IHttpContextAccessor>()
                              .HttpContext?.Request.Headers["x-site-code"],
    assemblies:
    [
        typeof(DefaultSiteProfile).Assembly,
        typeof(AlphaSiteProfile).Assembly,
        typeof(BravoSiteProfile).Assembly,
    ]);

// Wire a per-request service resolved by site key
builder.Services.AddSiteResolvedService<IOrderService>();

Each ISiteProfile.RegisterServices() registers its implementation as a keyed service:

services.AddKeyedScoped<IOrderService, AlphaOrderService>("ALPHA");

AddSiteResolvedService<IOrderService>() then adds a scoped factory that calls GetKeyedService<IOrderService>(siteId) at runtime, falling back to "default" if the site key is not found.

Source-generated profile (AOT-safe)

[GenerateSiteProfile("ALPHA", typeof(AlphaOrderContext))]
public partial class AlphaSiteProfile : ISiteProfile
{
    public string SiteId => "ALPHA";
    // RegisterServices() is generated by Muonroi.Tenancy.SiteProfile.SourceGenerators
}

Add the generator package alongside this one:

dotnet add package Muonroi.Tenancy.SiteProfile.SourceGenerators --prerelease

Features

  • ISiteProfile contract — implement once per site; RegisterServices() wires DbContext, repos, services, and mappers for that site.
  • AddSiteProfile<T>() — single-site registration; one binary, one profile.
  • AddMultiSiteProfiles() — reflection-based discovery of all ISiteProfile implementations across supplied assemblies; wires per-request ISiteProfileResolver.
  • AddMultiSiteProfilesCore() — AOT-safe overload; accepts pre-instantiated ISiteProfile[] from generated manifests.
  • AddSiteResolvedService<TService>() — registers a scoped factory that dispatches to the keyed service matching the current SiteId.
  • AddSiteConventionServices<TServiceInterface>() — convention-based scan: pairs each ISiteProfile with a matching TServiceInterface implementation by namespace proximity and registers them as keyed scoped services.
  • SiteProfileScopeAsyncLocal-backed scope that overrides the resolved profile for tests and background jobs.
  • SiteProfileOptions.StrictMode — when true, an unknown site code throws MInternalException instead of falling back to "default".
  • ISiteProfileBehavior + [SiteProfileBehavior(typeof(T))] — cross-cutting behaviors (e.g. audit logging) applied declaratively to a profile class.
  • ISiteEntityProfile<TCore, TSite> — compile-time constraint that enforces TSite : TCore for site entity hierarchies.
  • [GenerateSiteProfile(siteId, dbContextType)] — marks a partial ISiteProfile class for source-generator scaffolding of RegisterServices().
  • [SiteProfileAlias(targetSiteId)] — declares one site as an alias of another, reusing its service registrations.
  • [SiteEntityMap(coreType, siteType, table)] — runtime attribute carrying core↔site entity mapping metadata for source generators.
  • SiteProfileStartupValidator — hosted service that validates all registered site profiles at startup and logs failures.
  • AddSiteProfileRuleEngineIntegration() — opt-in bridge that registers ISiteProfileFactBagEnricher; injects __site.id and __site.profile into FactBag before rule orchestrator execution.

Configuration

builder.Services.ConfigureSiteProfile(o =>
{
    // Throw on unknown site codes instead of falling back to "default"
    o.StrictMode = true;

    // Assemblies to scan for ISiteProfile implementations (used by SiteProfileStartupValidator)
    o.SiteAssemblies = [typeof(AlphaSiteProfile).Assembly];
});

ConfigureSiteProfile calls services.Configure<SiteProfileOptions>(). Options can also be bound from appsettings.json via the standard services.Configure<SiteProfileOptions>(configuration.GetSection(...)) pattern.

Disable startup validation (testing / dev)

builder.Services.SkipSiteProfileStartupValidation();

Must be called after AddSiteProfile or AddMultiSiteProfiles.

Test isolation with SiteProfileScope

using (SiteProfileScope.ForSite(myTestProfile))
{
    // ISiteProfileResolver.Current returns myTestProfile for this async context
    var result = await sut.CreateOrderAsync(request);
}

API Reference

Type Purpose
ISiteProfile Per-site contract: SiteId, IsEnabled, RegisterServices()
SiteProfileExtensions ConfigureSiteProfile(), AddSiteProfile<T>(), AddSiteProfile(instance), AddMultiSiteProfiles(), AddMultiSiteProfilesCore(), AddSiteResolvedService<T>(), SkipSiteProfileStartupValidation()
SiteProfileConventionExtensions AddSiteConventionServices<TServiceInterface>() — convention-based keyed registration
ISiteProfileResolver Scoped: Current returns the active ISiteProfile for the request
SiteProfileResolver Default implementation of ISiteProfileResolver
SiteProfileScope ForSite(profile)AsyncLocal override for tests and background jobs
SiteProfileOptions StrictMode, SiteAssemblies
ISiteProfileBehavior Cross-cutting DI behavior applied via [SiteProfileBehavior]
ISiteEntityProfile<TCore, TSite> Compile-time TSite : TCore constraint marker
ISiteProfileFactBagEnricher Rule engine bridge — enriches FactBag with site identity
GenerateSiteProfileAttribute [GenerateSiteProfile(siteId, dbContextType)] — triggers source-generator scaffolding
SiteProfileAliasAttribute [SiteProfileAlias(targetSiteId)] — site-to-site alias
SiteEntityMapAttribute [SiteEntityMap(coreType, siteType, table)] — entity mapping metadata
SiteProfileBehaviorAttribute [SiteProfileBehavior(typeof(T))] — attaches a cross-cutting behavior
SiteProfileStartupValidator IHostedService — validates all profiles at startup

Samples

  • TestProject.Service — multi-site service with Alpha / Bravo / Charlie / Default profiles, [GenerateSiteProfile], [SiteProfileAlias], convention services, and gRPC site resolution

Compatibility

  • Target framework: net8.0
  • License: Apache-2.0 (OSS)

License

Apache-2.0. See LICENSE-APACHE.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on Muonroi.Tenancy.SiteProfile:

Package Downloads
Muonroi.Tenancy.SiteProfile.Web

ASP.NET Core middleware and SignalR hot-reload for Muonroi.Tenancy.SiteProfile.

Muonroi.Tenancy.SiteProfile.Grpc

gRPC site resolution interceptor for multi-site services. Extracts SiteCode from gRPC metadata and resolves ISiteProfile per request.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0-alpha.16 57 6/22/2026
1.0.0-alpha.15 96 5/31/2026
1.0.0-alpha.14 82 5/15/2026
1.0.0-alpha.13 93 5/2/2026
1.0.0-alpha.12 81 4/2/2026
1.0.0-alpha.11 122 4/2/2026
1.0.0-alpha.9 83 3/30/2026
1.0.0-alpha.8 324 3/28/2026
1.0.0-alpha.7 73 3/27/2026
1.0.0-alpha.5 66 3/27/2026
1.0.0-alpha.4 66 3/27/2026
1.0.0-alpha.3 63 3/27/2026
1.0.0-alpha.2 66 3/26/2026