Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save marcin-chwedczuk/769fd9f2f49da92508fb to your computer and use it in GitHub Desktop.
Save marcin-chwedczuk/769fd9f2f49da92508fb to your computer and use it in GitHub Desktop.
Scope per method call - custom scope
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