2011-02-09 10 views
6

Tengo un objeto multi-hilo que es caro para crear y debe estar disponible a través de mi aplicación (un Lucene.Net IndexReader).StructureMap 'Singleton condicional' para Lucene.Net IndexReader

El objeto puede dejar de ser válido, en cuyo momento tengo que volver a crearlo (IndexReader.IsCurrent es falso, necesita una nueva instancia con IndexReader.Reopen).

me gustaría poder usar un contenedor IoC (StructureMap) para gestionar la creación del objeto, pero no puedo averiguar si este escenario es posible. Se siente como una especie de ciclo de vida "singleton condicional".

¿Proporciona StructureMap tal característica? ¿Alguna sugerencia alternativa?

Respuesta

3

que probablemente utilice un alcance de PerRequest y no regresar al IndexReader directamente. En cambio, devolvería una abstracción del IndexReader que verificaría una referencia estática en el nivel de clase.

Luego, cuando se acceda a su propiedad en shim/proxy/abstracción, verificaría la referencia estática (lo haría seguro para subprocesos, por supuesto) y volvería a obtener el IndexReader si fuera necesario antes de devolverlo a el usuario.

+0

Estoy de acuerdo con casperOne. Piense en ocultar la instancia detrás de una interfaz/fachada para que pueda implementar estrategias más fácilmente, como la agrupación de objetos. – Steven

+0

Consideré esto, pero es una pena eliminar la responsabilidad de la creación de objetos y la gestión de la vida del contenedor IoC. Definitivamente funcionará para mí y será mi solución alternativa si no encuentro algo más centrado en la IoC. –

1

Al final me han ido para un objeto proxy simple que envuelve el IndexReader real y gestiona la reapertura. Como necesito usar la misma instancia de esto en las solicitudes, estoy usando StructureMap para proporcionar una instancia única de él. Código a continuación.

He investigado la creación de un StructureMap ILifecycle personalizado para manejar esta situación, pero no llegué lejos, vea 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; 
     } 
    } 
} 

y el registro StructureMap:

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

El contenido probablemente debería combinarse con la pregunta. – casperOne

+0

Si esta es una respuesta, probablemente debería ser aceptada. –

+0

El primer if (_indexReader.IsCurrent()) return; fuera del bloqueo puede arrojar una Lucene.Net.Store.AlreadyClosedException, que debe capturarse. Cuando este subproceso puede entrar en el bloqueo, el IndexReader se ha abierto de nuevo en el índice actual. – ENOTTY