How to use custom SolrNet calls with Sitecore


You have created custom SolrNet calls, but may have encountered the following exception:

Exception has been thrown by the target of an invocation.
---> Microsoft.Practices.ServiceLocation.ActivationException: 
Activation error occured while trying to get instance of type ISolrOperations`1, key "Some_index"
---> System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.

The issue is both Sitecore and SolrNet relies on a ServiceLocator to get Solr operations. When using SolrNet you initialize it like so:

Startup.Init<T>(_url);
_solr = ServiceLocator.Current.GetInstance<ISolrOperations<T>>();

Sitecore also initializes a custom locator provider.

ServiceLocator.SetLocatorProvider((ServiceLocatorProvider) (() => (IServiceLocator) new DefaultServiceLocator<Dictionary<string, object>>(this.Operations)));

Depending on which gets executed last, ServiceLocator.Current.GetInstance either resolves to Sitecore’s locator or SolrNet’s locator.

Solution

The solution is to create a service locator wrapper which switches between SolrNet’s service locator and Sitecore’s locator. We will then replace Sitecore’s DefaultSolrStartUp that sets the locator provider to our wrapper. Lastly, we will replace the InitializeSolrProvider which calls the DefaultSolrStartUp to our own SharedSolrStartUp.

Service Locator wrapper

public class SharedServiceLocator : IServiceLocator
{
   private const string SitecoreSolrDll = "Sitecore.ContentSearch.SolrProvider";
   IServiceLocator _sitecoreLocator;
   IServiceLocator _solrLocator;

   public SharedServiceLocator(IServiceLocator solrLocator)
   {
        _solrLocator = solrLocator;
   }

   public void SetSitecoreServiceLocator(IServiceLocator sitecoreLocator)
   {
       _sitecoreLocator = sitecoreLocator;
   }

   [MethodImplAttribute(MethodImplOptions.NoInlining)]
   IEnumerable<object> IServiceLocator.GetAllInstances(Type serviceType)
   {
       return (Assembly.GetCallingAssembly().FullName.StartsWith(SitecoreSolrDll) ? _sitecoreLocator : _solrLocator).GetAllInstances(serviceType);
   }

   [MethodImplAttribute(MethodImplOptions.NoInlining)]
   IEnumerable<TService> IServiceLocator.GetAllInstances<TService>()
   {
       return (Assembly.GetCallingAssembly().FullName.StartsWith(SitecoreSolrDll) ? _sitecoreLocator : _solrLocator).GetAllInstances<TService>();
   }

    [MethodImplAttribute(MethodImplOptions.NoInlining)]
    object IServiceLocator.GetInstance(Type serviceType)
    {
        return (Assembly.GetCallingAssembly().FullName.StartsWith(SitecoreSolrDll) ? _sitecoreLocator : _solrLocator).GetInstance(serviceType);
    }

    [MethodImplAttribute(MethodImplOptions.NoInlining)]
    object IServiceLocator.GetInstance(Type serviceType, string key)
    {
         return (Assembly.GetCallingAssembly().FullName.StartsWith(SitecoreSolrDll) ? _sitecoreLocator : _solrLocator).GetInstance(serviceType, key);
    }

    [MethodImplAttribute(MethodImplOptions.NoInlining)]
    TService IServiceLocator.GetInstance()
    {
        return (Assembly.GetCallingAssembly().FullName.StartsWith(SitecoreSolrDll) ? _sitecoreLocator : _solrLocator).GetInstance();
    }
    [MethodImplAttribute(MethodImplOptions.NoInlining)]
    TService IServiceLocator.GetInstance(string key)
    {
        return (Assembly.GetCallingAssembly().FullName.StartsWith(SitecoreSolrDll) ? _sitecoreLocator : _solrLocator).GetInstance(key);
    }
    [MethodImplAttribute(MethodImplOptions.NoInlining)]
    object IServiceProvider.GetService(Type serviceType)
    {
        return (Assembly.GetCallingAssembly().FullName.StartsWith(SitecoreSolrDll) ? _sitecoreLocator : _solrLocator).GetService(serviceType);
    } }

 

Shared Solr StartUp

Let's replace Sitecore’s DefaultSolrStartUp and set the locator provider to our wrapper. The majority of this code is borrowed from Sitecore's DefaultSolrStartUp.

public class SharedSolrStartUp : ISolrStartUp, IProviderStartUp
{
  private readonly DefaultSolrLocator<Dictionary<string, object>> operations;
    private readonly ISolrCache solrCache;
    private SharedServiceLocator _sharedServiceLocator;
    protected internal virtual DefaultSolrLocator<Dictionary<string, object>> Operations
    {
        get
        {
            return this.operations;
        }
    }
    public SharedSolrStartUp(SharedServiceLocator sharedServiceLocator)
    {
        if (SolrContentSearchManager.EnableHttpCache)
            this.solrCache = (ISolrCache)new HttpRuntimeCache();
        this.operations = new DefaultSolrLocator<Dictionary<string, object>>();
        _sharedServiceLocator = sharedServiceLocator;
    }
    public virtual void AddCore(string coreId, Type documentType, string coreUrl)
    {
        ISolrConnection connection = this.CreateConnection(coreUrl);
        this.Operations.AddCore(coreId, documentType, coreUrl, connection);
    }
    public virtual void Initialize()
    {
        if (!SolrContentSearchManager.IsEnabled)
            throw new InvalidOperationException("Solr configuration is not enabled. Please check your settings and include files.");
        this.Operations.DocumentSerializer = (ISolrDocumentSerializer<Dictionary<string, object>>)new SolrFieldBoostingDictionarySerializer(this.Operations.FieldSerializer);
        this.Operations.HttpWebRequestFactory = SolrContentSearchManager.HttpWebRequestFactory;
        this.Operations.SchemaParser = (ISolrSchemaParser)new Sitecore.ContentSearch.SolrProvider.Parsers.SolrSchemaParser();         foreach (string core in SolrContentSearchManager.Cores)
{
            this.AddCore(core, typeof(Dictionary<string, object>), string.Format("{0}/{1}", (object)SolrContentSearchManager.ServiceAddress, (object)core));             if (SolrContentSearchManager.EnableHttpCache)
                this.Operations.HttpCache = this.solrCache;
            this.Operations.CoreAdmin = this.BuildCoreAdmin();
            _sharedServiceLocator.SetSitecoreServiceLocator(new DefaultServiceLocator<Dictionary<string, object>>(this.Operations));
            ServiceLocator.SetLocatorProvider(() => _sharedServiceLocator);
            SolrContentSearchManager.SolrAdmin = (ISolrCoreAdmin)this.Operations.CoreAdmin;
            SolrContentSearchManager.Initialize();
        }
        public virtual bool IsSetupValid()
        {
            if (!SolrContentSearchManager.IsEnabled)
                return false;
            ISolrCoreAdminEx admin = this.BuildCoreAdmin();
            return SolrContentSearchManager.Cores.Select<string, CoreResult>((Func<string, CoreResult>)(defaultIndex => admin.Status(defaultIndex).First<CoreResult>())).All<CoreResult>
                  ((Func<CoreResult, bool>)(status => status.Name != null));
        }
        protected virtual ISolrCoreAdminEx BuildCoreAdmin()
        {
            return this.Operations.BuildCoreAdmin(this.CreateConnection(SolrContentSearchManager.ServiceAddress));
        }
        protected virtual ISolrConnection CreateConnection(string serverUrl)
        {
            SolrConnection solrConnection = new SolrConnection(serverUrl);
            solrConnection.Timeout = SolrContentSearchManager.ConnectionTimeout;
            if (this.solrCache != null)
                solrConnection.Cache = this.solrCache;
            return (ISolrConnection)solrConnection;
        }
}
}

 

Initialize pipeline

Here we will initialize SolrNet as well as Sitecore's.

using Microsoft.Practices.ServiceLocation;
using Sitecore.ContentSearch.SolrProvider;
using Sitecore.ContentSearch.SolrProvider.SolrNetIntegration;
using Sitecore.Pipelines;
using SolrNet;

namespace YourNameSpace
{
   public class InitializeSharedSolrProvider
   {
       public void Process(PipelineArgs args)
       {
            if (!SolrContentSearchManager.IsEnabled) return;

            if (IntegrationHelper.IsSolrConfigured())
            {
                IntegrationHelper.ReportDoubleSolrConfigurationAttempt(this.GetType());
            }
            else
            {
                Startup.Init<SomeObject1>("your solr url");
                Startup.Init<SomeObject2>("your solr url");

                //Place any custom SolrNet init prior to this line
                var sharedSolrStartUp = new SharedSolrStartUp(new SharedServiceLocator(ServiceLocator.Current));

            //init Sitecore's solr             sharedSolrStartUp.Initialize();         }     } } }

 

 

Sitecore Configuration

Lastly, we'll patch Sitecore to use your InitializeSharedSolrProvider pipeline.

<configuration>
  <sitecore>
    <pipelines>
      <initialize>
        <processor type="YourNameSpace.InitializeSharedSolrProvider, Assembly"
               patch:instead="*[@type='Sitecore.ContentSearch.SolrProvider.Pipelines.Loader.InitializeSolrProvider, Sitecore.ContentSearch.SolrProvider']"/>
      </initialize>
    </pipelines>
  </sitecore>
</configuration>
 
Categories: Sitecore

SEARCH ARTICLES

CATEGORIES

Sitecore 144
Commerce 100
Web Development 100
Sitecore Commerce 83
Sitecore Experience Commerce 9 64
Sitecore Experience Commerce 59
Content Management 55
eCommerce 48
B2B eCommerce 42
Sitecore Experience Platform 39
Sitecore Platinum Partner 39
Architecture 34
Insite 29
User Experience 26
Strategy 22
B2C eCommerce 21
B2B Commerce Blogs 21
commerceconnect 21
CloudCraze 20
SaaS (Software as a Service) 20
Cloud 17
Commerce Server 17
Salesforce B2B Commerce Cloud 16
Mobile 13
Search 13
Plugins 12
Analytics 12
Application Development 12
Digital Transformation 11
Sitecore Symposium 11
SPEAK 10
Helix 10
DMS 8
Social 8
Business Process 7
Authentication 7
5 Reasons 7
BI and Big Data 6
Data Visualization 6
Sitecore Presentation 6
Coveo 6
NET Development 5
Microsoft Azure 5
Automation 5
Front-End Development 4
SaaS (Software as a Service) 4
Digital Strategy 4
Brightcove 4
Press Release 4
Avalara Tax 3
Sitecore Experience Accelerator (SXA) 3
Sitecore Layouts 3
Video 3
SPE 3
Multi-site 3
Multi-lingual 3
Accessibility 3
Habitat 3
Vault 3
Identity 2
Managed Services 2
CDN 2
SMB 2
Cryptocurrency 2
Sitecore Forms 2
Sitecore Experience Commerce 9 Promotions 2
Uncategorized 2
EXM 2
Conversational Commerce 2
Sitecore SaaS 2
Security 2
Unit Testing 2
Headless Architecture 2
Sitecore Experience Awards 2
Google 1
Content Delivery Network 1
Configure Price Quote 1
CPQ 1
Blockchain 1
Coupons 1
Sitecore Rss 1
Artificial Intelligence 1
Machine Learning 1
Okta 1
RFP Process 1
NoSQL 1
Flex Accelerator for Sitecore 1
Reviews 1
SEO 1
Page Labels 1