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

CallContextLifetimeScope

Provides explicit lifetime scoping within logical path of execution. Used for types with Scoped.
using Castle.Core; using Castle.Core.Internal; using Castle.Windsor; 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> appDomainLocalInstanceCache = new ConcurrentDictionary<Guid, CallContextLifetimeScope>(); private static readonly AsyncLocal<Guid> asyncLocal = new AsyncLocal<Guid>(); private readonly Guid contextId; private readonly Lock lock = Lock.Create(); private readonly CallContextLifetimeScope parentScope; private ScopeCache cache = new ScopeCache(); public CallContextLifetimeScope(IKernel container) : this() { } public CallContextLifetimeScope() { CallContextLifetimeScope callContextLifetimeScope = ObtainCurrentScope(); if (callContextLifetimeScope != null) parentScope = callContextLifetimeScope; contextId = Guid.NewGuid(); appDomainLocalInstanceCache.TryAdd(contextId, this); SetCurrentScope(this); } public CallContextLifetimeScope(IWindsorContainer container) : this() { } [SecuritySafeCritical] public void Dispose() { IUpgradeableLockHolder val = lock.ForReadingUpgradeable(); try { if (cache == null) return; val.Upgrade(); cache.Dispose(); cache = null; if (parentScope != null) SetCurrentScope(parentScope); } finally { ((IDisposable)val)?.Dispose(); } appDomainLocalInstanceCache.TryRemove(contextId, out CallContextLifetimeScope _); } public Burden GetCachedInstance(ComponentModel model, ScopedInstanceActivationCallback createInstance) { IUpgradeableLockHolder val = lock.ForReadingUpgradeable(); try { Burden burden = cache[model]; if (burden == null) { val.Upgrade(); burden = createInstance(delegate { }); cache[model] = burden; } return burden; } finally { ((IDisposable)val)?.Dispose(); } } [SecuritySafeCritical] private void SetCurrentScope(CallContextLifetimeScope lifetimeScope) { asyncLocal.Value = lifetimeScope.contextId; } [SecuritySafeCritical] public static CallContextLifetimeScope ObtainCurrentScope() { Guid value = asyncLocal.Value; appDomainLocalInstanceCache.TryGetValue(value, out CallContextLifetimeScope value2); return value2; } } }