<PackageReference Include="Castle.Windsor" Version="6.0.0" />

CallContextLifetimeScope

Provides explicit lifetime scoping within logical path of execution. Used for types with Scoped.
using Castle.Core; using Castle.MicroKernel.Internal; using System; using System.Collections.Concurrent; using System.Security; using System.Threading; namespace Castle.MicroKernel.Lifestyle.Scoped { public class CallContextLifetimeScope : ILifetimeScope, IDisposable { private static readonly ConcurrentDictionary<Guid, CallContextLifetimeScope> allScopes = new ConcurrentDictionary<Guid, CallContextLifetimeScope>(); private static readonly AsyncLocal<Guid> asyncLocal = new AsyncLocal<Guid>(); private readonly Guid contextId = Guid.NewGuid(); private readonly CallContextLifetimeScope parentScope; private readonly Castle.MicroKernel.Internal.Lock lock = Castle.MicroKernel.Internal.Lock.Create(); private ScopeCache cache = new ScopeCache(); public CallContextLifetimeScope() { contextId = Guid.NewGuid(); parentScope = ObtainCurrentScope(); allScopes.TryAdd(contextId, this); SetCurrentScope(this); } [SecuritySafeCritical] public void Dispose() { using (IUpgradeableLockHolder upgradeableLockHolder = lock.ForReadingUpgradeable()) { if (cache == null) return; upgradeableLockHolder.Upgrade(); cache.Dispose(); cache = null; if (parentScope != null) SetCurrentScope(parentScope); } allScopes.TryRemove(contextId, out CallContextLifetimeScope _); } public Burden GetCachedInstance(ComponentModel model, ScopedInstanceActivationCallback createInstance) { using (IUpgradeableLockHolder upgradeableLockHolder = lock.ForReadingUpgradeable()) { Burden burden = cache[model]; if (burden == null) { upgradeableLockHolder.Upgrade(); burden = createInstance(delegate { }); cache[model] = burden; } return burden; } } [SecuritySafeCritical] private static void SetCurrentScope(CallContextLifetimeScope lifetimeScope) { asyncLocal.Value = lifetimeScope.contextId; } [SecuritySafeCritical] public static CallContextLifetimeScope ObtainCurrentScope() { object obj = asyncLocal.Value; if (!(obj is Guid)) return null; allScopes.TryGetValue((Guid)obj, out CallContextLifetimeScope value); return value; } } }