6

Sto utilizzando EntityFramework e implementando un repository generico e un modello unit-of-work in un gruppo di classi di lavoro in background. Le classi di lavoro vengono create utilizzando Unity DI in modo che possano essere iniettate con le dipendenze, che sono principalmente repository e l'oggetto UnitOfWork. I repository e l'unità di lavoro dovrebbero condividere l'EF DbContext.Unity PerThreadLifetimeManager e Task

Un lavoro comune sarebbe simile a questa:

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

Tutti i lavori vengono eseguiti all'interno di nuovi compiti, qualcosa di simile

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

E ho registrato l'unità-di-lavoro e repository con Unity utilizzando PerThreadLifetimeManager, pensando che ciò consentirebbe la condivisione delle istanze registrate nel contesto di un'attività (e in quell'unico oggetto di lavoro), ma non all'esterno.

Il problema che sto riscontrando è che a volte i lavori vengono iniettati con oggetti disposti, il che ovviamente non è molto bello. Ho letto che Task.Factory.StartNew() non usa sempre un nuovo thread. Significa che lo PerThreadLifetimeManager condividerà gli oggetti tra le attività? Se questo è vero, esiste un altro modo di gestire l'oggetto liftime con l'unità, che consentirebbe a ciascuna attività di lavorare in isolamento, indipendentemente dal thread su cui è in esecuzione?

EDIT:

Mentre la risposta selezionata sotto raggiungerà la stessa cosa, ho finito per usare le HierarchicalLifetimeManager e bambino contenitori per ottenere l'isolamento dipendenza per ciascun lavoro.

Ecco un esempio:

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

risposta

6

Si ottiene gli oggetti disposti in quanto biblioteca parallela utilizza un pool di thread, e Unity restituisce lo stesso oggetto per lo stesso filo della piscina.

Se si utilizza il contenitore nel modo in cui è stato pubblicato, suggerisco di utilizzare PerResolveLifetimeManager. In questo modo, quando si risolve un oggetto, l'intero grafico di risoluzione condivide la stessa istanza, ma l'istanza è univoca per risoluzione: ogni attività avrà una propria istanza quando chiama Resolve.

+1

La tua risposta è corretta, ma volevo solo aggiungere che ho finito per usare un 'HieararchicalLiftetimeManager' e creare un contenitore figlio nell'attività. Questo perché avevo bisogno di usare il container per risolvere dinamicamente alcuni servizi da una delle classi di lavoro. So che usare un container come un localizzatore di servizi è un odore di codice, ma è così che viene impostato, e non c'è tempo ora di aggiustarlo ... – Pinetree

+1

@Pinetree Qualche possibilità di mostrare come hai fatto? Grazie – nfplee

+0

@nfplee Non ho il codice a casa e non me lo ricordo in cima alla mia testa. Pubblicherò quello che ho fatto lunedì quando andrò al lavoro. – Pinetree