Created
January 30, 2016 09:21
-
-
Save marcin-chwedczuk/769fd9f2f49da92508fb to your computer and use it in GitHub Desktop.
Scope per method call - custom scope
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Concurrent; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Threading; | |
using System.Threading.Tasks; | |
using Castle.Core; | |
using Castle.DynamicProxy; | |
using Castle.MicroKernel; | |
using Castle.MicroKernel.Context; | |
using Castle.MicroKernel.Lifestyle; | |
using Castle.MicroKernel.Lifestyle.Scoped; | |
using Castle.MicroKernel.Registration; | |
using Castle.Windsor; | |
namespace WindsorCastle.UnitOfWork | |
{ | |
public interface ITransient | |
{ | |
void DoSomething(); | |
} | |
public class Transient : ITransient, IDisposable | |
{ | |
public Transient() | |
{ | |
Console.WriteLine("TRANSIENT CREATED ON TID: {0}", Thread.CurrentThread.ManagedThreadId); | |
} | |
public void DoSomething() | |
{ | |
Console.WriteLine("TRANSIENT DoSomething()"); | |
} | |
public void Dispose() | |
{ | |
Console.WriteLine("DISPOSING TRANSIENT ON THREAD: {0}", Thread.CurrentThread.ManagedThreadId); | |
} | |
} | |
public interface ISingleton | |
{ | |
void DoSomething(); | |
} | |
public class Singleton : ISingleton, IDisposable | |
{ | |
public Singleton() | |
{ | |
Console.WriteLine("SINGLETON CREATED ON TID: {0}", Thread.CurrentThread.ManagedThreadId); | |
} | |
public void DoSomething() | |
{ | |
Console.WriteLine("SINGLETON DoSomething()"); | |
} | |
public void Dispose() | |
{ | |
Console.WriteLine("DISPOSING SINGLETON"); | |
} | |
} | |
public interface IUnitOfWorkManager | |
{ | |
void Execute(); | |
} | |
[Interceptor(typeof(PerMethodCallScopeInterceptor))] | |
public class UnitOfWorkManager : IUnitOfWorkManager | |
{ | |
private readonly IKernel kernel; | |
public UnitOfWorkManager(IKernel kernel) | |
{ | |
if (kernel == null) throw new ArgumentNullException(nameof(kernel)); | |
this.kernel = kernel; | |
} | |
public void Execute() | |
{ | |
kernel.Resolve<ITransient>().DoSomething(); | |
kernel.Resolve<ISingleton>().DoSomething(); | |
} | |
} | |
public static class PerMethodCallScopeManager | |
{ | |
private static readonly ConcurrentDictionary<int, ILifetimeScope> scopes = new ConcurrentDictionary<int, ILifetimeScope>(); | |
public static void OpenScopeForCurrentThread() | |
{ | |
Console.WriteLine("Create new scope for thread: {0}.", GetCurrentThreadId()); | |
int threadId = GetCurrentThreadId(); | |
ILifetimeScope newScope = new DefaultLifetimeScope(new ScopeCache()); | |
scopes.AddOrUpdate(threadId, newScope, (tid, oldScope) => | |
{ | |
throw new InvalidOperationException("Scope is already open for this thread - this may mean bug in code or attempt to create nested scope."); | |
}); | |
} | |
public static void CloseScopeForCurrentThread() | |
{ | |
Console.WriteLine("Remove scope for thread: {0}.", GetCurrentThreadId()); | |
int threadId = GetCurrentThreadId(); | |
ILifetimeScope scope; | |
if (scopes.TryRemove(threadId, out scope)) | |
{ | |
scope.Dispose(); | |
} | |
} | |
public static ILifetimeScope GetScopeForCurrentThread() | |
{ | |
int threadId = GetCurrentThreadId(); | |
ILifetimeScope scope; | |
if (scopes.TryGetValue(threadId, out scope)) | |
{ | |
return scope; | |
} | |
return null; | |
} | |
private static int GetCurrentThreadId() => Thread.CurrentThread.ManagedThreadId; | |
} | |
public class PerMethodCallScopeAccessor : IScopeAccessor | |
{ | |
public ILifetimeScope GetScope(CreationContext context) | |
{ | |
return PerMethodCallScopeManager.GetScopeForCurrentThread(); | |
} | |
public void Dispose() | |
{ | |
ILifetimeScope scope = PerMethodCallScopeManager.GetScopeForCurrentThread(); | |
scope?.Dispose(); | |
} | |
} | |
[Serializable] | |
public class PerMethodCallScopeInterceptor : IInterceptor | |
{ | |
public void Intercept(IInvocation invocation) | |
{ | |
PerMethodCallScopeManager.OpenScopeForCurrentThread(); | |
try | |
{ | |
invocation.Proceed(); | |
} | |
finally | |
{ | |
PerMethodCallScopeManager.CloseScopeForCurrentThread(); | |
} | |
} | |
} | |
public class Program | |
{ | |
static void Main(string[] args) | |
{ | |
IWindsorContainer container = new WindsorContainer(); | |
container.Register( | |
Component | |
.For<ITransient>() | |
.ImplementedBy<Transient>() | |
.LifestyleScoped<PerMethodCallScopeAccessor>(), | |
Component | |
.For<ISingleton>() | |
.ImplementedBy<Singleton>() | |
.LifestyleSingleton(), | |
Component | |
.For<IUnitOfWorkManager>() | |
.ImplementedBy<UnitOfWorkManager>() | |
.LifestyleTransient(), | |
Component | |
.For<PerMethodCallScopeInterceptor>() | |
.LifestyleSingleton() | |
); | |
IUnitOfWorkManager mgr = container.Resolve<IUnitOfWorkManager>(); | |
Parallel.For(0, 10000, i => | |
{ | |
mgr.Execute(); | |
}); | |
container.Release(mgr); | |
Console.ReadLine(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment