我有几个循环,每个循环都通过ConcurrentQueue<T>产生异步进程。这些过程调用某些业务服务实现,这些实现使用存储库进行数据库交互。所有服务实现都是通过StructureMap连接的。

存储库实现具有一些特征,需要仔细管理:


正在使用的数据库技术为Redis
该实现使用ServiceStack.net的Redis客户端(通过PooledRedisClientManager)。
几种方法使用的事务(我相信)不能由同一RedisClient同时创建。因此,不可能在多个异步进程上共享单个存储库实现,因为它将尝试同时创建多个事务。
为了释放内存和数据库连接,需要显式地放置这些对象-这样,我在存储库类上实现了IDisposable。
没有理由不能在单个异步过程的范围内共享存储库实例,因为不会有并发请求/事务。


考虑到以上几点,我想将单个存储库实例的作用域限定为每个异步进程的生存期。

要记住的一件事是,与异步进程范围一起使用的服务也被系统的具有不同生存期特征的其他部分使用(例如,在网站中,存储库的范围限于页面的生存期)请求)。

我将尝试用一些代码(从我的代码简化)来说明:

该程序管理队列(并连接执行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 );
    }
}


我认为这可以解释情况和目标。我的问题如下:


我可以如上所述使用StructureMap在单个过程的上下文中使用不同的范围。
我不想在我的域/服务层中包括对StructureMap的直接依赖关系。因此,如果我现在可以使用其他范围,是否有一种简单的方法可以做到这一点,而无需直接从流程本身内部调用StructureMap?
是否可以通过DSL配置指示StructureMap在流程结束时处置存储库,还是需要在代码中显式地执行此操作?

最佳答案

您可以在这种情况下使用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>();

关于c# - StructureMap:特定上下文中的自定义生命周期范围,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9584099/

10-17 00:45