Unity PerThreadLifetimeManager 和 Tasks

6
我正在使用EntityFramework,并在一些后台作业类中实现通用存储库和工作单元模式。使用Unity DI创建作业类,以便可以注入依赖项,其中大多数是存储库和UnitOfWork对象。存储库和工作单元应该共享EF DbContext。
常见的作业如下:
public class CommonJob : IJob, IDisposable
{        
    private IRepo<SomeEntity> _repo;
    private IUnitOfWork _uow;

    public CommonJob(IRepo<SomeEntity> repo, IUnitOfWork uow)
    {
        _repo = repo;
        _uow = uow;
    }

    public void RunJob()
    {
        // do stuff here
    }

    public void Dispose()
    {
        _uow.Commit();
        _uow.Dispose();
    }
}

所有的作业都在新任务中运行,类似于这样。
Task.Factory.StartNew(() => {
    // container is UnityContainer
    var job = container.Resolve<CommonJob>();
    job.RunJob();
    job.Dispose();
});

我已经使用PerThreadLifetimeManager将工作单元和存储库注册到Unity中,认为这样可以在一个任务的上下文中共享注册实例(以及在那个作业对象中),但不在外面。

我遇到的问题是有时作业将被注入处置对象,这显然不太好。我读到Task.Factory.StartNew()并非总是使用新线程。这是否意味着PerThreadLifetimeManager将在任务之间共享对象?如果是这样,是否有另一种管理统一对象生命周期的方法,允许每个任务在隔离状态下工作,而不管它正在运行的线程是什么?

编辑:

虽然下面选择的答案将实现相同的功能,但我最终使用了HierarchicalLifetimeManager和子容器来为每个作业实现依赖项隔离。

这里是一个示例:

// registering the dependencies, 
// these should be singletons, but only within the context of one job
_container.Register(typeof(IRepo<>), typeof(Repo<>), new HierarchicalLifetimeManager())
          .Register<IUnitOfWork, UnitOfWork>(new HierarchicalLifetimeManager());

// starting a new job
Task.Factory.StartNew<IUnityContainer>(() => 
{
    // create a child container to remove instance sharing between tasks
    var childContainer = _container.CreateChildContainer();

    // figure out and resolve the job class from the child container
    // this will make sure that different jobs do not share instances
    var jobType = GetJobType();
    var job = childContainer.Resolve(jobType) as IJob;

    job.RunJob();

    return childContainer;
}).ContinueWith(previousTask => {
    // when the job is done, dispose of the child container
    task.Result.Dispose(); 
});
1个回答

6
你会得到被处理的对象,因为并行库使用线程池,而Unity为池中相同的线程返回相同的对象。
如果您按照您发布的方式使用容器,我建议您使用PerResolveLifetimeManager。 这样,当您解析一个对象时,整个解析图共享相同的实例,但是每次解析都是唯一的:每个任务在调用Resolve时都将拥有自己的实例。

1
你的答案是正确的,但我想补充一下,我最终使用了HieararchicalLiftetimeManager并在任务中创建了一个子容器。这是因为我需要使用容器来动态解析某些作业类中的一些服务。我知道使用容器作为服务定位器是一种代码异味,但这就是它的设置方式,现在没有时间去修复它... - Ivan Pintar
@nfplee 我家里没有代码,也想不起来了。星期一上班时我会把我做的东西发出来。 - Ivan Pintar
2
@nfplee 我最近很忙,所以花了一些时间,但我终于编辑了问题并包含了我的解决方案,其中使用了HieararchicalLiftetimeManager - Ivan Pintar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接