2010-07-03 12 views
6

[OR] Jak określić żywotność StructureMap do UOW do spożycia przez żądania HTTP i pracy kwarcuStructureMap zwraca umieszczoną nHibenrate sesji przedmiotu z nici zasięgu lokalnego

mam tę aplikację internetową, która wykorzystuje SM, dla IoC. Używam zakresu HybridHttpOrThreadLocalScoped do przechowywania moich obiektów NHibernate ISession. Działa to dobrze w sesji na modę zapytania dla moich żądań internetowych.

Ale mam również quartz.net, który planuje kilka zadań. Zadanie korzysta z tej samej jednostki pracy, aby uzyskać obiekt ISession. W tym scenariuszu, gdy program planujący rozpoczyna zadanie, wszystko działa poprawnie na początku, a zadanie działa dobrze przez kilka razy, WCZEŚNIEJ identyfikator wątku zadania zostanie powtórzony.

Wyobraź sobie, że gdy zadanie jest zaplanowane, zaczyna działać w wątkach z identyfikatorami 11, 12, 13, a następnie ponownie z identyfikatorem wątku 11. W tym momencie structuremap zwraca obiekt sesji, który jest już usuwany i otrzymuję "System.ObjectDisposedException: Session is closed!" błąd.

Z tego co widzę, sesja jest przechowywana w lokalnym magazynie wątków, a po zakończeniu sesji na końcu jednostki pracy obiekt sesji jest nadal przechowywany w lokalnym magazynie wątków. Wygląda na to, że po zakończeniu wątku jego lokalna pamięć nie zostanie wyczyszczona iw jakiś sposób po utworzeniu nowego wątku o tym samym identyfikatorze, structuremap wyszukuje sesję w starym wątku lokalnego magazynu (który ma zostać wyczyszczony dla nowego wątku Wierzę) i zwraca obiekt sesji, który jest już usuwany.

Pytania:

  1. Czy istnieje sposób, aby wyczyścić pamięć lokalna wątku (na zakończenie)?
  2. Czy istnieje odpowiednik opcji "ReleaseAndDisposeAllHttpScopedObjects" dla obiektów o zakresie gwintu?
  3. Czy istnieje sposób na unieważnienie (lub wyrzucenie) unieszkodliwionego obiektu, więc nawet jeśli SM go szuka, to nie znajdzie żadnego i będzie musiał utworzyć nowe wystąpienie?

Mam nadzieję, że moje pytanie było jasne. To zajęło mi kilka godzin mojego czasu i wciąż nie znalazłem sposobu na obejście tego. Doceniam wszelkie podpowiedzi:>

Aktualizacja: dodałem własne rozwiązanie, aby dokonać UOW podawane przez pracę StructureMap z obu żądań HTTP i pracy kwarcowych. Daj mi znać, jeśli masz lepsze/łatwiejsze/prostsze rozwiązanie.

+0

Zarządzasz swoim kwarcowy IJobs z StructureMap? –

+0

@Mauricio: Używam StructureMap w mojej aplikacji. Nie jestem pewien, co masz na myśli, zarządzając robotami kwarcowymi przez StructeMap:> – kaptan

+0

to twoje kwarcowe IJob zarządzane przez StructureMap? Innymi słowy: czy rejestrujesz swoje prace w kontenerze? –

Odpowiedz

1

Dlaczego nie utworzyć nowej sesji dla zadań kwarcowych? Jednostką pracy jest zazwyczaj operacja transakcyjna na db. Nie mogę sobie wyobrazić, by kwarcowe zlecenia były transakcyjnie powiązane z żądaniami/odpowiedziami internetowymi. Tworzenie nowych sesji nie jest drogie. Czy to możliwe?

+0

Tak. Chcę stworzyć nową sesję dla każdego zadania kwarcowego. Ale ponieważ używam idei UoW, chcę, aby była spójna w mojej aplikacji. Nie chcę więc tworzyć sesji bezpośrednio dla zadań kwarcu. Chcę utworzyć instancję UoW. Ale w tym samym czasie chcę użyć StructureMap, aby uzyskać instancję UoW. Dlatego właśnie zdefiniowałem hybrydowy cykl życia w StructeMap dla mojego UoW, tak aby zwracał odpowiednią wartość dla każdego żądania http lub każdego wykonania kwarcu. – kaptan

+0

@kaptan: Zgadzam się z @rcravens. To, co zrobiłem, to uzyskać instancję ISessionFactory (ObjectFactory.GetInstance ()) i otworzyć nową sesję po uruchomieniu mojej pracy. – LeftyX

2

Wracałem do tego, co zrobiłem, aby StructureMap pracował z UoW na Http i UoW na kwarcową robotę i zdecydowałem się udostępnić tutaj moje rozwiązanie.

Pomysł polegał na tym, że chciałem użyć zakresu Hybrid StructureMap, aby uzyskać instancję UoW, gdy istnieje kontekst http, a także uzyskać inną instancję UoW na wątek, gdy nie ma kontekstu http (jak w przypadku kwarcu pożary). W ten sposób:

For<IUnitOfWork>().HybridHttpOrThreadLocalScoped().Use<UnitOfWork>(); 

The UoW dla http działało bez zarzutu. Problem polegał na tym, że w każdym wątku.

Oto, co się dzieje. Po uruchomieniu zadania quratz pociąga za wątek z puli wątków i rozpoczyna wykonywanie zadania za pomocą tego wątku. Kiedy zaczyna się praca, proszę o zamówienie. StructureMap sprawdza w lokalnym magazynie dla tego wątku, aby zwrócić UoW, ale ponieważ nie może znaleźć żadnego, tworzy go i zapisuje w lokalnej pamięci wątku. Dostaję UU, następnie perfom Begin, Commit, Dispose i wszystko jest w porządku.

Problem występuje, gdy wątek jest wyciągany z puli wątków, która była używana wcześniej, aby zwolnić zadanie (i użyła UUW). W tym przypadku, gdy żądasz UUW, StructureMap wyszukuje w pamięci podręcznej (wątek lokalny) i znajduje UUW i zwraca go Tobie. Ale problem polega na tym, że UoW jest zbywana!

Tak naprawdę nie możemy używać funkcji UoW na wątek dla zadań kwarcowych, ponieważ same nici nie są utylizowane i przechowują stare, przechowywane w pamięci podręcznej pliki UoW. Zasadniczo cykl życia nici nie pasuje do cyklu życia kwarcu. Dlatego stworzyłem własny cykl życiowy do pracy kwarcowej.

Najpierw tworzę własną klasę cyklu http-kwarc hybrydowy życia:

public class HybridHttpQuartzLifecycle : HttpLifecycleBase<HttpContextLifecycle, QuartzLifecycle> 
{ 
    public override string Scope { get { return "HybridHttpQuartzLifecycle"; } } 
} 

Następnie tworzę klasę QuartzLifecyle:

public class QuartzLifecycle : ILifecycle 
{ 

    public void EjectAll() 
    { 
     FindCache().DisposeAndClear(); 
    } 

    public IObjectCache FindCache() 
    { 
     return QuartzContext.Cache; 
    } 

    public string Scope { get { return "QuartzLifecycle"; } } 
} 

Potem trzeba stworzyć jakąś klasę kontekstowe jak HttpContext kwarcu do przechowywania informacji związanych z kontekstem. Dlatego stworzyłem klasę QuartzContext. Po uruchomieniu kwarcowego zadania, JobExecutionContext dla tego zadania powinien zostać zarejestrowany w QuartzContext. Następnie faktyczna pamięć podręczna (MainObjectCache) dla instancji StructureMap zostanie utworzona w tym konkretnym JobExecutionContext. Tak więc po zakończeniu wykonywania zadania pamięć podręczna również zniknie i nie będziemy mieć problemu z usunięciem UoW z pamięci podręcznej.

Również od _jobExecutionContext jest ThreadStatic, gdy kiedykolwiek zażądamy cache z QuartzContext, zwróci pamięć podręczną z JobExecutionContext, który jest zapisany dla tego samego wątku. Tak więc, gdy wiele zadań jest uruchomionych w tym samym czasie, ich JobExecutionContexts są zapisywane osobno, a my będziemy mieć oddzielne pamięci podręczne dla każdego uruchomionego zadania.

public class QuartzContext 
{ 

    private static readonly string _cacheKey = "STRUCTUREMAP-INSTANCES"; 

    [ThreadStatic] 
    private static JobExecutionContext _jobExecutionContext; 

    protected static void Register(JobExecutionContext jobExecutionContext) 
    { 
     _jobExecutionContext = jobExecutionContext; 
     _jobExecutionContext.Put(_cacheKey, new MainObjectCache()); 
    } 

    public static IObjectCache Cache 
    { 
     get 
     { 
      return (IObjectCache)_jobExecutionContext.Get(_cacheKey); 
     } 
    } 
} 

Mam klasę abstrakcyjną o nazwie BaseJobSingleSession, z której pochodzą inne zadania. Ta klasa rozszerza klasę QuartzContext. Widać, że rejestruję JobExecutionContext po uruchomieniu zadania.

abstract class BaseJobSingleSession : QuartzContext, IStatefulJob 
{ 
    public override void Execute(JobExecutionContext context) 
    { 
     Register(context); 
     IUnitOfWork unitOfWork = ObjectFactory.GetInstance<IUnitOfWork>(); 

     try 
     { 
      unitOfWork.Begin(); 

      // do stuff .... 

      unitOfWork.Commit(); 
     } 
     catch (Exception exception) 
     { 
      unitOfWork.RollBack(); 

     } 
     finally 
     { 
      unitOfWork.Dispose(); 
     } 
    } 
} 

końcu zdefiniowany cykl życia dla UOW: (. W cyklu życia i klas kontekstu Spojrzałem do kodu źródłowego StructureMap aby uzyskać pomysł)

For<IUnitOfWork>().LifecycleIs(new HybridHttpQuartzLifecycle()).Use<UnitOfWork>(); 

Proszę podzielić Twoje pomysły, komentarze i sugestie:>