2011-02-09 20 views
6

Mam obiekt bezpieczny dla wątków, który jest drogi w tworzeniu i musi być dostępny za pośrednictwem mojej aplikacji (Lucene.Net IndexReader).StructureMap 'conditional singleton' dla Lucene.Net IndexReader

Obiekt może stać się nieważny, w którym to momencie muszę go odtworzyć (IndexReader.IsCurrent jest fałszywy, potrzebuję nowej instancji za pomocą IndexReader.Reopen).

Chciałbym móc użyć kontenera IoC (StructureMap) do zarządzania tworzeniem obiektu, ale nie mogę się domyślić, czy ten scenariusz jest możliwy. Wydaje się, że jest to cykl życia "warunkowego singletonu".

Czy StructureMap udostępnia taką funkcję? Jakieś alternatywne sugestie?

Odpowiedz

3

Prawdopodobnie użyłbym zakresu PerRequest i nie zwrócę bezpośrednio do IndexReader. Zamiast tego zwróciłabym abstrakcję z IndexReader, która wykonałaby sprawdzenie statycznego odniesienia na poziomie klasy.

Następnie, gdy twoja własność na shim/proxy/abstrakcji jest dostępna, to sprawdzi statyczny numer referencyjny (oczywiście sprawi, że będzie bezpieczny w wątkach) i ponownie pobierze numer IndexReader, zanim będzie dostarczony z powrotem do użytkownik.

+0

zgadzam się z casperOne. Pomyśl o ukryciu instancji za interfejsem/elewacją, aby łatwiej było wdrażać strategie, takie jak łączenie obiektów. – Steven

+0

Zastanawiałem się nad tym, ale szkoda jest usuwać resposibiliy do tworzenia obiektów i zarządzania ich na całe życie z kontenera IoC. To na pewno zadziała dla mnie i będzie moim rozwiązaniem, jeśli nie wymyślę czegoś bardziej skoncentrowanego na IoC. –

1

W końcu poszedłem na prosty obiekt proxy, który otacza rzeczywisty IndexReader i zarządza ponowne otwarcie. Ponieważ potrzebuję użyć tego samego wystąpienia tego w poprzek żądań, używam StructureMap, aby zapewnić jego pojedynczą instancję. Kod poniżej.

Badałem tworzenie niestandardowego ILifecycle StructureMap, aby poradzić sobie z tą sytuacją, ale nie zaszły daleko, zobacz this question.

public class IndexReaderProxy 
{ 
    private IndexReader _indexReader; 
    private readonly object _indexReaderLock = new object(); 

    public IndexReaderProxy(Directory directory, bool readOnly) 
    { 
     _indexReader = IndexReader.Open(directory, readOnly); 
    } 

    public IndexReader GetCurrentIndexReader() 
    { 
     ReopenIndexReaderIfNotCurrent(); 
     return _indexReader; 
    } 

    private void ReopenIndexReaderIfNotCurrent() 
    { 
     if (_indexReader.IsCurrent()) return; 
     lock (_indexReaderLock) 
     { 
      if (_indexReader.IsCurrent()) return; 
      var newIndexReader = _indexReader.Reopen(); 
      _indexReader.Close(); 
      _indexReader = newIndexReader; 
     } 
    } 
} 

I rejestracja StructureMap:

For<IndexReaderProxy>().Singleton().Use(
      new IndexReaderProxy(FSDirectory.Open(new DirectoryInfo(LuceneIndexPath)), true) 
     ); 
+0

Treść powinna prawdopodobnie zostać połączona z pytaniem. – casperOne

+0

Jeśli jest to odpowiedź, prawdopodobnie powinna zostać zaakceptowana. –

+0

Pierwszy if (_indexReader.IsCurrent()) zwraca; poza blokadą można rzucić Lucene.Net.Store.AlreadyClosedException, który powinien zostać przechwycony. Gdy ten wątek może wejść do blokady, IndexReader został ponownie otwarty na bieżącym indeksie. – ENOTTY