我有几个循环,每个循环通过ConcurrentQueue<T>
生成异步进程。这些进程调用一些使用存储库进行数据库交互的业务服务实现。服务实现都是通过StructureMap连接的。
存储库实现具有一些需要仔细管理的特性:
PooledRedisClientManager
)。考虑到上述情况,我想将单个存储库实例的范围限定为每个异步进程的生命周期。
要记住的一件事是,与异步进程范围一起使用的服务也被系统的其他部分使用,这些部分具有不同的生命周期特征(例如,在存储库范围为生命周期的网站中)页面请求)。
我将尝试用一些代码(从我的代码中简化)来说明:
管理队列的程序(并连接执行IAsyncResult
调用的事件处理程序):
public class Program
{
private readonly ConcurrentQueue<QueueItem> queue = new ConcurrentQueue<QueueItem>();
private readonly IItemManager itemManager; // implemented via constructor DI.
public void ProcessQueueItems()
{
while ( queue.Count > 0 || shouldContinueEnqueuing )
{
QueueItem item;
if ( queue.TryDequeue( out item ) )
{
// Begin async process here - only one repository should be used within the scope of this invocation
// (i.e. withing the scope of the itemManager.ProcessItem( item ) method call.
new ItemProcessor( itemMananger.ProcessItem ).BeginInvoke( e.Item, ItemCallback, null );
}
Thread.Sleep( 1 );
}
}
private static void ItemCallback( IAsyncResult result )
{
var asyncResult = ( AsyncResult ) result;
var caller = ( ItemProcessor ) asyncResult.AsyncDelegate;
var outcome = caller.EndInvoke( result );
// Do something with outcome...
}
private delegate ItemResult ItemProcessor( QueueItem item );
}
异步结果调用的实现。我想在ProcessItem( ... )
方法中管理范围:
public class ItemManager : IItemManager
{
private readonly IServiceA serviceA; // implemented via constructor DI.
private readonly IServiceB serviceB; // implemented via constructor DI.
public ItemResult ProcessItem( QueueItem item )
{
// Both serviceA and serviceB use the repository which is injected via StructureMap. They should share
// the instance and at the end of the process it should be disposed (manually, if needs be).
var something = serviceA.DoSomething( item );
return serviceB.GetResult( something );
}
}
我认为这解释了情况和目标。我的问题如下:
答案 0 :(得分:1)
您可以使用nested container来处理这种情况。
嵌套容器将跟踪它的所有瞬态对象 创建。当嵌套容器本身被释放时,它将调用 Dispose()在它创建的任何瞬态对象上。
var nestedContainer = container.GetNestedContainer();
var processor = nestedContainer.GetInstance<IItemProcessor>();
确保每个对象使用相同存储库的其他方法是使用With()方法
// Get the IRepository which should be shared
// This object is registered using simple
// For<ISession>.Use<Session> registration so not scoped
// http context or anything like that
var session = container.GetInstance<ISession>();
// Create instance of IProcessor using the specific instance
// of ISession. If multiple classes in the object grap use ISession
// they will get the same instance. Note that you can use multiple
// With() statements
var itemProcessor = container.With(session).GetInstance<IItemProcessor>();