Rosher Consulting

Software Consulting and Development Services

Using multiple Solr URLs with SolrNetFacility and Castle Windsor

The current project I’m working on involves moving the generation of various product feeds from a console application into a new administration website that uses HangFire to schedule when these feeds should generate, so we’ve gone from setting up our IoC container individually for each feed in a console app, to setting it up once for all feeds in a website and this is where we’ve hit the problem of configuring the SolrNetFacility as some feeds talk to our live Solr index and some talk to our staging Solr index.

The Solr docs contain some information on this with their Multi-core / multi-instance documentation page, however they don’t quite give a full example, for instance this is how they resolve a specific Solr instance:

ISolrOperations<Product> solrProduct1 = container.Resolve<ISolrOperations<Product>>("core0-id"); // use proper Windsor service overrides instead of resolving like this

Their own comment says that you should use service overrides instead of resolving as in the example, but it would be nice if they could give an example service override.

If you Google for answers you’ll come across various posts asking the same question, which while in this example, the maintainer of Solr.NET is the one actually answering (and he does in fairness provide the correct answer), he still doesn’t elaborate over and above the documentation, which may seem pedantic but if you’re going to give an example at least give one that is complete.

Additionally, in our case we’re using ISolrReadOnlyOperations<> rather than ISolrOperations<> as in their example, so it wasn’t immediately obvious if we could do a service override or whether we would have to switch to ISolrOperations<> instead. However a quick look at the source code for the SolrNetFacility over on GitHub helped clarify how the multi-core / multi-instance setup works.

How to implement multiple Solr URLs

Firstly, as per the Solr.NET example, you need to set up your SolrNetFacility and then register your cores/instances (note: the URLs for each core do not need to be on the same server or same port):

var solrNetFacility = new SolrNetFacility("http://localhost:8983/LiveSolr");
solrNetFacility.AddCore("live", typeof(Product), "http://localhost:8983/LiveSolr");
solrNetFacility.AddCore("staging", typeof(Product), "http://localhost:8983/StagingSolr");
container.AddFacility("solr", solrNetFacility);

The documentation implies that the URL passed in to the constructor becomes the default, however in my testing the first core added becomes the default and this is what Castle Windsor will resolve and pass in to your classes, which means that the URL you pass in to the constructor also needs to be added as the first core, so that this becomes the default.

Once you’ve setup the separate cores/instances, you need to setup your service overrides.

As I’ve previously said, we use ISolrReadOnlyOperations<> as opposed to ISolrOperations<>, the underlying class that implements these two interfaces is the same, so Castle Windsor will resolve the correct Solr instance when we specify the dependency as ISolrReadOnlyOperations<>, like so:

container.Register(
    Component.For<MyFeed>().DependsOn(
        Dependency.OnComponent(typeof(ISolrReadOnlyOperations<Product>), "staging"),
    )
);

If you then run your app and debug into the creation of “MyFeed” you’ll see that the Solr connection passed in to your class is the one you’re expecting.

Comments are closed