J'utilise EntityFramework
et implémente un référentiel générique et un modèle d'unité de travail dans un tas de classes de travaux d'arrière-plan. Les classes d'emplois sont créées à l'aide de Unity DI afin qu'elles puissent être injectées avec les dépendances, qui sont principalement des référentiels et l'objet UnitOfWork
. Les référentiels et l'unité de travail doivent partager le fichier EF DbContext
.Unity PerThreadLifetimeManager et tâches
Un travail commun ressemblerait à ceci:
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();
}
}
Tous les travaux sont exécutés dans de nouvelles tâches, quelque chose comme ça
Task.Factory.StartNew(() => {
// container is UnityContainer
var job = container.Resolve<CommonJob>();
job.RunJob();
job.Dispose();
});
Je suis donc inscrit l'unité de travail et dépôts avec Unity en utilisant le PerThreadLifetimeManager
, en pensant que cela permettrait de partager les instances enregistrées dans le contexte d'une tâche (et dans ce même objet de travail), mais pas à l'extérieur.
Le problème que j'ai est que parfois les travaux seront injectés avec des objets disposés, ce qui n'est évidemment pas très agréable. J'ai lu que Task.Factory.StartNew()
n'utilise pas toujours un nouveau thread. Est-ce que cela signifie que le PerThreadLifetimeManager
partagera des objets entre les tâches? Si cela est vrai, existe-t-il une autre façon de gérer la durée de vie de l'objet avec unité, ce qui permettrait à chaque tâche de fonctionner isolément, quel que soit le thread sur lequel il s'exécute?
EDIT:
Bien que la réponse choisie ci-dessous atteindra la même chose, je fini par utiliser les conteneurs HierarchicalLifetimeManager
et de l'enfant pour obtenir l'isolement de dépendance pour chaque emploi.
Voici un exemple:
// 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();
});
Votre réponse est correcte, mais je voulais juste ajouter que j'ai fini par utiliser un 'HieararchicalLiftetimeManager' et en créant un conteneur enfant dans la tâche. C'est parce que j'avais besoin d'utiliser le conteneur pour résoudre dynamiquement certains services de l'une des classes de travail. Je sais que l'utilisation d'un conteneur en tant que localisateur de service est une odeur de code, mais c'est comme ça que ça se passe, et il n'y a pas de temps pour le réparer ... – Pinetree
@Pinetree Une chance de montrer comment tu as fait? Merci – nfplee
@ nfplee Je n'ai pas le code à la maison et je ne m'en souviens pas du haut de ma tête. Je posterai ce que j'ai fait lundi quand je serai au travail. – Pinetree