6

Używam EntityFramework i implementuję ogólny wzorzec repozytorium i jednostki pracy w grupie klas zadań w tle. Klasy zadań są tworzone przy użyciu Unity DI, dzięki czemu mogą zostać wstrzyknięte zależności, które w większości są repozytoriami i obiektem UnitOfWork. Repozytoria i jednostki pracy powinny współdzielić EF DbContext.Unity PerThreadLifetimeManager i zadania

Wspólna praca będzie wyglądać następująco:

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

Wszystkie zadania są uruchamiane w nowych zadań, coś takiego

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

A ja zarejestrował unit-of-pracy i repozytoriów z Unity przy użyciu PerThreadLifetimeManager, myśląc, że to pozwoliłoby na współdzielenie zarejestrowanych instancji w kontekście jednego zadania (i jednego obiektu zadania), ale nie na zewnątrz.

Kwestia, którą mam, polega na tym, że czasami prace zostaną wstrzyknięte rozrzuconymi przedmiotami, co oczywiście nie jest zbyt miłe. Czytałem, że Task.Factory.StartNew() nie zawsze używa nowego wątku. Czy to oznacza, że ​​PerThreadLifetimeManager będzie współdzielić obiekty między zadaniami? Jeśli to prawda, czy istnieje inny sposób zarządzania czasem życia obiektu z jednością, który pozwoliłby każdemu zadaniu pracować w izolacji, niezależnie od wątku, na którym działa?

EDIT:

Gdy wybrana odpowiedź poniżej będzie osiągnąć to samo, skończyło się używając HierarchicalLifetimeManager i dziecko pojemniki do osiągnięcia izolacji zależnościach dla każdego zadania.

Oto przykład:

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

Odpowiedz

6

Otrzymasz rozmieszczonych obiektów, ponieważ biblioteka równolegle korzysta z puli wątków i Unity powraca ten sam obiekt do tego samego wątku basenu.

Jeśli używasz kontenera w sposób, który wysłałeś, sugeruję, aby użyć PerResolveLifetimeManager. W ten sposób podczas rozwiązywania obiektu cały wykres rozdzielczości współużytkuje tę samą instancję, ale instancja jest unikalna dla każdej rozdzielczości: każde zadanie będzie miało swoją własną instancję, gdy wywoła Resolve.

+1

Twoja odpowiedź jest poprawna, ale chciałem tylko dodać, że skończyłem używając 'HieararchicalLiftetimeManager' i stworzyłem kontener potomny w zadaniu. Wynika to z konieczności użycia kontenera do dynamicznego rozwiązania niektórych usług z jednej z klas zadań. Wiem, że używanie kontenera jako lokalizatora usług jest zapachem kodu, ale tak to jest skonfigurowane i nie ma czasu, aby to naprawić ... – Pinetree

+1

@Pinetree Czy była jakaś szansa, aby pokazać, jak to zrobiłeś? Dzięki – nfplee

+0

@nfplee Nie mam kodu w domu i nie pamiętam tego z mojej strony. Opublikuję to, co zrobiłem w poniedziałek, kiedy dostanę pracę. – Pinetree