Stashbox by Peter Csajtai

<PackageReference Include="Stashbox" Version="5.5.2-preview-768" />

 TenantDistributor

Represents a tenant distributor that manages tenants in a multi-tenant environment.
using Stashbox.Utils; using Stashbox.Utils.Data; using Stashbox.Utils.Data.Immutable; using System; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; namespace Stashbox.Multitenant { [System.Runtime.CompilerServices.NullableContext(1)] [System.Runtime.CompilerServices.Nullable(0)] public sealed class TenantDistributor : ITenantDistributor, IAsyncDisposable, IDisposable { private int disposed; private ImmutableTree<object, IStashboxContainer> tenantRepository = ImmutableTree<object, IStashboxContainer>.Empty; public IStashboxContainer RootContainer { get; } [System.Runtime.CompilerServices.NullableContext(2)] public TenantDistributor(IStashboxContainer rootContainer = null) { RootContainer = (rootContainer ?? new StashboxContainer(null)); } public void ConfigureTenant(object tenantId, Func<IStashboxContainer, IDisposable> tenantConfig) { IStashboxContainer stashboxContainer = RootContainer.CreateChildContainer(null); if (Swap.SwapValue<object, IStashboxContainer, byte, byte, ImmutableTree<object, IStashboxContainer>>(ref tenantRepository, (object id, IStashboxContainer container, byte _, byte _, ImmutableTree<object, IStashboxContainer> repo) => repo.AddOrUpdate(id, container, false, false), tenantId, stashboxContainer, 0, 0)) { IDisposable disposable = tenantConfig(stashboxContainer); RootContainer.ContainerContext.RootScope.AddDisposableTracking(disposable); } } [return: System.Runtime.CompilerServices.Nullable(2)] public IDependencyResolver GetTenant(object tenantId) { return tenantRepository.GetOrDefaultByValue(tenantId); } public void Validate() { ExpandableArray<Exception> expandableArray = new ExpandableArray<Exception>(); try { RootContainer.Validate(); } catch (AggregateException ex) { expandableArray.Add(new AggregateException("Root container validation failed. See the inner exceptions for details.", ex.InnerExceptions)); } foreach (ReadOnlyKeyValue<object, IStashboxContainer> item in tenantRepository.Walk()) { try { item.Value.Validate(); } catch (AggregateException ex2) { expandableArray.Add(new AggregateException($"""{item.Key}""", ex2.InnerExceptions)); } } if (expandableArray.Length > 0) throw new AggregateException("Tenant distributor validation failed. See the inner exceptions for details.", expandableArray); } public void Dispose() { if (Interlocked.CompareExchange(ref disposed, 1, 0) == 0) RootContainer.Dispose(); } public ValueTask DisposeAsync() { if (Interlocked.CompareExchange(ref disposed, 1, 0) != 0) return new ValueTask(Task.CompletedTask); return RootContainer.DisposeAsync(); } } }