Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unity PerThreadLifetimeManager and Tasks

I'm using EntityFramework and implementing a generic repository and unit-of-work pattern in a bunch of background job classes. The jobs classes are created using Unity DI so that they can be injected with the dependencies, which are mostly repositories and the UnitOfWork object. Repositories and the unit-of-work should share the EF DbContext .

A common job would look like this:

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();
    }
}

All jobs are run within new tasks, something like this

Task.Factory.StartNew(() => {
    // container is UnityContainer
    var job = container.Resolve<CommonJob>();
    job.RunJob();
    job.Dispose();
});

And I've registered the unit-of-work and repositories with Unity using the PerThreadLifetimeManager, thinking that that would allow sharing the registered instances within the context of one task (and in that one job object), but not outside.

The issue that I'm having is that sometimes the jobs will get injected with disposed objects, which is obviously not very nice. I've been reading that Task.Factory.StartNew() does not always use a new thread. Does this mean that the PerThreadLifetimeManager will share objects between tasks? If this is true, is there another way of managing the object liftime with unity, which would allow for each task to work in isolation, regardless of the thread it's running on?

EDIT:

While the selected answer below will achieve the same thing, I ended up using the HierarchicalLifetimeManager and child containers to achieve dependency isolation for each job.

Here's an example:

// 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(); 
});
like image 693
Ivan Pintar Avatar asked Aug 19 '13 07:08

Ivan Pintar


1 Answers

You get disposed objects because parallel library uses a thread pool, and Unity returns the same object for the same thread of the pool.

If you use the container in the way you posted, I suggest you to use PerResolveLifetimeManager. This way, when you resolve an object the whole resolution graph shares the same instance but the instance is unique per resolution: each task will have its own instance when it calls Resolve.

like image 190
onof Avatar answered Oct 02 '22 22:10

onof