2

I'm trying to use SolrNet in a command line application (or more accurately, from LINQPad) to test some queries, and when trying to initialize the library, I get the following error:

Key 'SolrNet.Impl.SolrConnection.UserQuery+Resource.SolrNet.Impl.SolrConnection' already registered in container

However, if I catch this error and continue, the ServiceLocator gives me the following error:

Activation error occured while trying to get instance of type ISolrOperations`1, key ""

With the inner exception:

The given key was not present in the dictionary.

My full code looks like this:

try
{
    Startup.Init<Resource>("http://localhost:8080/solr/");
    Console.WriteLine("Initialized\n");
}
catch (Exception ex)
{
    Console.WriteLine("Already Initialized: " + ex.Message);
}

// This line causes the error if Solr is already initialized
var solr = ServiceLocator.Current.GetInstance<ISolrOperations<Resource>>();

// Do the search
var results = solr.Query(new SolrQuery("title:test"));

I'm running Tomcat 7 on Windows 7x64 with Solr 3.4.0 installed.

There's another message about the same problem on StackOverflow, though the accepted answer of putting the Startup.Init code in Global.asax is only relevant to ASP.NET.

Restarting the Tomcat7 service resolves the problem, but having to do this after every query is a pain.

What is the correct way to use the SolrNet library to interact with Solr from a C# console application?

Community
  • 1
  • 1
Mun
  • 14,098
  • 11
  • 59
  • 83

2 Answers2

6

The correct way to use SolrNet in a console application is to only execute the line

 Startup.Init<Resource>("http://localhost:8080/solr/");

once for the life of your console application. I typically put it as the first line in my Main method as shown below...

static void Main(string[] args)
{
     Startup.Init<Resource>("http://localhost:8080/solr/");

     //Call method or do work to query from solr here... 
     //Using your code in a method...
     QuerySolr();
}

private static void QuerySolr()
{
     var solr = ServiceLocator.Current.GetInstance<ISolrOperations<Resource>>();

     // Do the search
     var results = solr.Query(new SolrQuery("title:test"));
}

Your error is coming from the fact that you are trying to initialize the SolrNet connection multiple times. You only need to initialize it once when the console application starts and then reference (look up) via the ServiceLocator when needed.

Paige Cook
  • 22,415
  • 3
  • 57
  • 68
  • If this is the case, shouldn't wrapping the Startup.Init in a try/catch block resolve the issue? That way, even if it was called multiple times and caused the 'already registered in container' error, the service locator would still be able to get an instance and allow the rest of the code to run properly. I'm currently running this code in LINQPad, so maybe that's part of the problem. I'll try running it as a standard console app and see if that makes any difference. – Mun Feb 22 '12 at 16:43
  • Not necessarily, I am guessing that when you initialize it the second time, you are corrupting the entry and making it unusable. (But I am not positive, since I do not know the inner workings of the ServiceLocator IOC container). Hence the Activation error that are seeing when trying to query. So catching the exception and continuing on in spite of it is not going to work. – Paige Cook Feb 22 '12 at 16:47
  • I do believe that running in LINQPad may be part of the issue, as I have about 10 different console apps using SolrNet without any issues. – Paige Cook Feb 22 '12 at 16:55
  • 5
    Had a look through the LINQPad settings, and I think you were right about the SolrNet connection being initialized multiple times. It looks like the application domain is re-used, which was causing this. Going into Preferences -> Advanced and setting the "Always use fresh application domains" to true seems to have resolved the problem (requires LINQPad to be restarted). Thanks for your help. – Mun Feb 22 '12 at 16:55
  • @Mun : or simply run Startup.Init once, then delete it from your LINQPad editor so you don't run it again. – Mauricio Scheffer Feb 22 '12 at 17:43
  • @MauricioScheffer The query is only cached for a while, so the initialization code would still need to be run when LINQPad decides to load the appdomain again. Commenting & uncommenting the line seems like a bit of a dance, and simply forcing a fresh app domain to be loaded by changing the setting seems like a much easier option, with minimal side effects. – Mun Feb 22 '12 at 17:53
2

My Solution is clear Startup before Init

Startup.Container.Clear();
Startup.InitContainer();
Startup.Init<Resource>("http://localhost:8080/solr/");
Truc
  • 386
  • 4
  • 12
  • this is most useful for me- especially i use it in LinqPad to play around with the query. – YS. Feb 10 '16 at 20:14