6

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

Répondre

6

Vous obtenez des objets disposés en parallèle parce que la bibliothèque utilise un pool de threads, et l'unité retourne le même objet pour le même fil de la piscine.

Si vous utilisez le conteneur de la manière que vous avez posté, je vous suggère d'utiliser PerResolveLifetimeManager. Ainsi, lorsque vous résolvez un objet, le graphe de résolution entier partage la même instance mais l'instance est unique par résolution: chaque tâche aura sa propre instance lorsqu'elle appelle Resolve.

+1

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

+1

@Pinetree Une chance de montrer comment tu as fait? Merci – nfplee

+0

@ 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