5

After manually implementing support for the Edm.GeographyPoint field type (per Is it possible to get Azure Search to support EDM.GeographyPoint?), I was happy to notice an answer on a related question from Dawid Rutkowski (Using Sitecore SXA Location Search with Azure Search) indicating that the SXA team has implemented this same functionality.

I've converted my custom index configurations over to use the relevant SXA types (e.g. Sitecore.XA.Foundation.Search.Providers.Azure.CloudSearchProviderIndex). I'm able to rebuild my index in Sitecore and see good values in the Azure index, for example:

...
"geo_coordinate": {
  "type": "Point",
  "coordinates": [
    -90.169,
    33.4945
  ],
  "crs": {
    "type": "name",
    "properties":
    {
      "name": "EPSG:4326"
    }
  }
}
...

Now, I'm trying to query the index using the Sitecore search API and am getting the following run-time error:

Constructor on type 'Sitecore.XA.Foundation.Search.Providers.Azure.LinqToCloudIndex`1[[Acme.Foundation.Search.Models.FooResult, Acme.Foundation.Search, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' not found.

at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, StackCrawlMark& stackMark)
   at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
   at System.Activator.CreateInstance(Type type, Object[] args)
   at Sitecore.XA.Foundation.Search.Providers.Azure.CloudSearchProviderIndex.<>c.<InitializeServiceCollectionClient>b__2_0(ServiceBuilder builder)
   at Sitecore.ContentSearch.Azure.ServiceCollection.GetInstance(Type concreteType, Object[] args)
   at Sitecore.ContentSearch.Azure.ServiceCollection.GetInstance[T](Object[] args)
   at Sitecore.ContentSearch.Azure.CloudSearchSearchContext.GetQueryable[TItem](IExecutionContext[] executionContexts)
   at Acme.Foundation.Search.Repositories.FooRepository.GetFoos(...)
...

Here are my index configurations:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:search="http://www.sitecore.net/xmlconfig/search/">
  <sitecore search:require="azure">
    <contentSearch>
      <indexConfigurations>
        <defaultAzureFoosIndexConfiguration ref="contentSearch/indexConfigurations/defaultCloudIndexConfiguration">
          <fieldMap ref="contentSearch/indexConfigurations/defaultCloudIndexConfiguration/fieldMap">
            <fieldNames hint="raw:AddFieldByFieldName">
              <field fieldName="geo_coordinate" boost="1f" facetable="NO" type="Sitecore.XA.Foundation.Search.Providers.Azure.Geospatial.GeoPoint" settingType="Sitecore.ContentSearch.Azure.CloudSearchFieldConfiguration, Sitecore.ContentSearch.Azure" />
            </fieldNames>
          </fieldMap>
          <documentOptions ref="contentSearch/indexConfigurations/defaultCloudIndexConfiguration/documentOptions">
            <fields hint="raw:AddComputedIndexField">
              <field fieldName="geo_coordinate">Acme.Foundation.Search.ComputedFields.CoordinateComputedIndexField, Acme.Foundation.Search</field>
            </fields>
          </documentOptions>
        </defaultAzureFoosIndexConfiguration>
    </indexConfigurations>
    </contentSearch>
  </sitecore>
</configuration>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/" xmlns:search="http://www.sitecore.net/xmlconfig/search/" xmlns:tenant="http://www.sitecore.net/xmlconfig/tenant/">
  <sitecore role:require="Standalone or ContentManagement or ContentDelivery" search:require="azure">
    <contentSearch>
      <configuration type="Sitecore.ContentSearch.ContentSearchConfiguration, Sitecore.ContentSearch">
        <indexes hint="list:AddIndex">
          <index id="foo_web_index" type="Sitecore.XA.Foundation.Search.Providers.Azure.CloudSearchProviderIndex, Sitecore.XA.Foundation.Search.Providers.Azure">
            <param desc="name">$(id)</param>
            <param desc="connectionStringName">cloud.search</param>
            <param desc="totalParallelServices">5</param>
            <param desc="propertyStore" ref="contentSearch/indexConfigurations/databasePropertyStore" param1="$(id)" />
            <configuration ref="contentSearch/indexConfigurations/defaultAzureFoosIndexConfiguration" />
            <strategies hint="list:AddStrategy">
              <strategy ref="contentSearch/indexConfigurations/indexUpdateStrategies/onPublishEndAsync" />
            </strategies>
            <commitPolicyExecutor type="Sitecore.ContentSearch.CommitPolicyExecutor, Sitecore.ContentSearch">
              <policies hint="list:AddCommitPolicy">
                <policy type="Sitecore.ContentSearch.TimeIntervalCommitPolicy, Sitecore.ContentSearch" />
                <policy type="Sitecore.ContentSearch.ModificationCountCommitPolicy, Sitecore.ContentSearch">
                  <Limit>1000</Limit>
                </policy>
              </policies>
            </commitPolicyExecutor>
            <locations hint="list:AddCrawler">
              <crawler type="Sitecore.ContentSearch.SitecoreItemCrawler, Sitecore.ContentSearch">
                <Database>web</Database>
                <Root>/sitecore/content/Tenant/Global/Foos/</Root>
              </crawler>
            </locations>
            <enableItemLanguageFallback>false</enableItemLanguageFallback>
            <enableFieldLanguageFallback>false</enableFieldLanguageFallback>
          </index>
        </indexes>
      </configuration>
    </contentSearch>
  </sitecore>
</configuration>

I'm creating the search context as per usual:

var ctx = ContentSearchManager.GetIndex("foo_web_index").CreateSearchContext();

...and am querying the index like so:

var results = ctx.GetQueryable<FooResult>().Where(...)...;

The run-time error is thrown on this line (on GetQueryable<T>()).

What I have verified/tried thus far:

  • My custom index configs are patched after Sitecore.XA.Foundation.Search.Azure.config (...\App_Config\Modules\SXA\Z.Foundation.Overrides\Sitecore.XA.Foundation.Search.Azure.config) and should therefore pick up all the SXA goodness.
  • There aren't ostensibly any <param /> elements I'm missing.
  • The run-time type of the search context is Sitecore.XA.Foundation.Search.Providers.Azure.CloudSearchSearchContext, as expected.
  • Inheriting from SearchResultItem on FooResult doesn't change the error.
  • Adding a parameterless constructor on FooResult doesn't change the error.
  • Referencing an OOTB SXA index rather than the custom index (e.g. sitecore_sxa_web_index) yields the same error; it doesn't seem to be unique to the index.

Reflecting Sitecore.XA.Foundation.Search.Providers.Azure.dll, I think this is the method interest:

protected virtual ServiceCollectionClient InitializeServiceCollectionClient()
{
  ServiceCollectionClient collectionClient = new ServiceCollectionClient();
  collectionClient.Register(typeof (LinqToCloudIndex<>), (Func<ServiceBuilder, object>) (builder => ServiceBuilder.CreateInstanceOfType(typeof (LinqToCloudIndex<>), builder.Types.ToArray<Type>(), (object) builder.Arguments)));
  collectionClient.Register(typeof (AbstractSearchIndex), (Func<ServiceBuilder, object>) (builder => (object) this));
  collectionClient.Register(typeof (QueryStringBuilder), (Func<ServiceBuilder, object>) (builder => (object) new QueryStringBuilder(new FilterQueryBuilder(), new SearchQueryBuilder(), true)));
  return collectionClient;
}

Specifically this line:

collectionClient.Register(typeof (LinqToCloudIndex<>), (Func<ServiceBuilder, object>) (builder => ServiceBuilder.CreateInstanceOfType(typeof (LinqToCloudIndex<>), builder.Types.ToArray<Type>(), (object) builder.Arguments)));

As this is reflected code, the empty <> probably indicates a cast but, I got nothing 😊.

What am I missing?

  • Something in the configs?
  • Some fancy thing with DI?
  • A specific way to instantiate the search context?

Version notes:

  • Sitecore XP 9.1.1 rev. 002459
  • Sitecore Experience Accelerator 1.8.1 rev. 190319
  • 1
    have you tried using FooResult using the sitecore_web_index to rule out the index itself being the issue? – Ben Lipson Jun 13 at 17:48
  • 1
    Yes, we have implemented geospatial features in SXA. They are not available out of the box in Sitecore. That is the reason why we have our own overrides for LinqToCloudIndex or CloudSearchProviderIndex. Those need to be used in order to have properly working features like ordering by distance or searching within a radius. Few questions... What version of SXA do you have? Why you have custom geo_coordinate fields instead of SXA ones? Why are you using custom computed field type Acme.Foundation.Search.ComputedFields.CoordinateComputedIndexField instead of SXA one? – Dawid Rutkowski Jun 13 at 18:04
  • @DawidRutkowski Thanks for the comment! We're using Sitecore XP 9.1.1 rev. 002459 with Sitecore Experience Accelerator 1.8.1 rev. 190319. I have a custom template that also has a coordinate field; I wanted to use a custom geo_coordinate field just to keep things separate and avoid collision/confusion. The custom computed field exists for the same reason and is keyed to my own coordinate field. – nsturdivant Jun 13 at 20:43
  • @BenLipson That's a good idea. I'll try that and report back. – nsturdivant Jun 13 at 20:55
  • @BenLipson Temporarily hard coding the index name as "sitecore_sxa_web_index" (meaning ContentSearchManager.GetIndex("sitecore_sxa_web_index").CreateSearchContext())...yields the same error. So it doesn't appear to be unique to the custom index. – nsturdivant Jun 14 at 3:38
1

I had exactly the same issue and 'fixed' it by creating an extension method that creates a new LinqToCloudIndex<TItem>. I say 'fixed' because I was not able to identify the exact cause of the problem. But by recreating the LinqToCloudIndex I was able to overcome the error. The best solution would be a proper fix by Sitecore.

Here are the details of my solution. First let's take a look at the LinqToCloudIndex Class. The constructor takes the following 3 arguments:

LinqToCloudIndex(CloudSearchSearchContext context, IExecutionContext[] executionContexts, ServiceCollectionClient serviceCollectionClient);

In my extension method I pass the latter 3 arguments.

  • CloudSearchSearchContext: I cast my IProviderSearchContext to the CloudSearchSearchContext
  • IExecutionContext[]: I don't use any ExecutionContext so I pass null
  • ServiceCollectionClient: I recreate a new instance of ServiceCollectionClient

The extension method

using Sitecore.ContentSearch;
using Sitecore.ContentSearch.Azure;
using Sitecore.ContentSearch.Azure.Query;
using System.Linq;

namespace Foundation.Search.Extensions
{
    public static class SearchExtensions
    {
        public static IQueryable<TItem> GetMyQueryable<TItem>(this IProviderSearchContext context, bool isAzure)
        {
            if (isAzure)
            {
                // create new LinqToCloudIndex in order to overcome the error:
                // Constructor on type 'Sitecore.XA.Foundation.Search.Providers.Azure.LinqToCloudIndex`1[[xxx]]' not found.
                var linqToCloudIndex = new LinqToCloudIndex<TItem>((CloudSearchSearchContext)context, null, new ServiceCollectionClient());
                return linqToCloudIndex.GetQueryable();
            }

            // just return the GetQueryable when using Solr or Lucene
            return context.GetQueryable<TItem>();
        }
    }
}

Using the extension method

As you can see i'm using context.GetMyQueryable instead of context.GetQueryable:

using (var context = ContentSearchManager.GetIndex("yourindex").CreateSearchContext())
{
    string searchDefine = Sitecore.Configuration.Settings.GetAppSetting("search:define");
    var results = context.GetMyQueryable<MySearchResultItem>(searchDefine.Equals("Azure", System.StringComparison.CurrentCulture)).Where(...)...
}

Version notes

  • Sitecore XM 9.1.0 (rev. 001564)
  • Sitecore Experience Accelerator 1.8 rev. 181112 for 9.1
  • I'm accepting this answer because it does seem to be a viable workaround for the original issue. However, per my comments on the question, Sitecore did issue a hotfix to address the run-time exception I was seeing. – nsturdivant Dec 4 at 5:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.