StructureMap 'conditional singleton' for Lucene.Net IndexReader
I have a threadsafe object that is expensive to create and needs to be available through my application (a Lucene.Net IndexReader).
The object can become invalid, at which point I need to recreate it (IndexReader.IsCurrent is false, need a new instance using IndexReader.Reopen).
I'd like to able to use an IoC container (StructureMap) to manage the creation of the object, but I can't work out if this scenario is possible. It feels like some kind of "开发者_开发技巧conditional singleton" lifecycle.
Does StructureMap provide such a feature? Any alternative suggestions?
I would probably use a scope of PerRequest
and not return the IndexReader
directly. Instead, I'd return an abstraction of the IndexReader
which would perform a check on a static reference held on the class level.
Then, when your property on the shim/proxy/abstraction is accessed, it would check the static reference (you would make it thread-safe, of course) and re-get the IndexReader
if needed before delivering it back to the user.
In the end I have gone for a simple proxy object that wraps the actual IndexReader and manages the Reopening. As I need to use the same instance of this across requests I am using StructureMap to provide a singleton instance of it. Code below.
I've investigated creating a custom StructureMap ILifecycle to handle this situation, but didn't get to far, see 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;
}
}
}
And the StructureMap registration:
For<IndexReaderProxy>().Singleton().Use(
new IndexReaderProxy(FSDirectory.Open(new DirectoryInfo(LuceneIndexPath)), true)
);
精彩评论