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();
});
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With