<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.Globalization; using System.Runtime.Remoting.Messaging; using System.Security; namespace Castle.MicroKernel.Lifestyle.Scoped { public class CallContextLifetimeScope : ILifetimeScope, IDisposable { private static readonly ConcurrentDictionary<Guid, CallContextLifetimeScope> appDomainLocalInstanceCache = new ConcurrentDictionary<Guid, CallContextLifetimeScope>(); private static readonly string keyInCallContext = "castle.lifetime-scope-" + AppDomain.CurrentDomain.Id.ToString(CultureInfo.InvariantCulture); 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); else CallContext.FreeNamedDataSlot(keyInCallContext); } 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) { CallContext.LogicalSetData(keyInCallContext, (object)lifetimeScope.contextId); } [SecuritySafeCritical] public static CallContextLifetimeScope ObtainCurrentScope() { object obj = CallContext.LogicalGetData(keyInCallContext); if (obj == null) return null; appDomainLocalInstanceCache.TryGetValue((Guid)obj, out CallContextLifetimeScope value); return value; } } }