Context.Site and SecurityState are not preserved for computed indexed fields


Description

Search indexes are rebuilt and updated in multiple threads to improve indexing speed.

The parallelism is implemented on several levels:

By default, search indexes are updated in the context of the shell site.
However, the context site information might be lost for computed index fields. Code that accesses Context.Site might fail with an error. For example, the following errors might occur when building an item URL during indexing:

ERROR Error in CustomComputedField
Exception: System.NullReferenceException
Message: Object reference not set to an instance of an object.
Source: Sitecore.Kernel
at Sitecore.Links.UrlBuilders.ItemUrlBuilder.AddServer(UrlBuildModel model, ItemUrlBuilderOptions options)
at Sitecore.Links.UrlBuilders.BaseUrlBuilder`1.BuildUrl(UrlBuildModel model, TOptions options)

or

WARN Could not compute value for ComputedIndexField
Exception: System.NullReferenceException
Message: Object reference not set to an instance of an object.
Source: Sitecore.Kernel
at Sitecore.Links.UrlBuilders.DefaultMediaUrlBuilderOptions.get_Site()
at Sitecore.Links.UrlBuilders.MediaUrlBuilderOptions.get_Site()
at Sitecore.Links.UrlBuilders.MediaUrlBuilder.AddServer(UrlBuildModel model, MediaUrlBuilderOptions options)
at Sitecore.Links.UrlBuilders.BaseUrlBuilder`1.BuildUrl(UrlBuildModel model, TOptions options)

By default, search indexes are updated in the context of a SecurityDisabler. This means that all items and all fields can be accessed by the indexing process with no permission checks overhead.
However, the SecurityDisabler might be inactive for computed index fields. The indexing process might be unable to access some items or fields.

Solution

Option 1

Disable parallel indexing of the computed index fields by creating a configuration patch file in the \App_Config\Include\zzz folder:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/">
  <sitecore>
    <settings>
      <setting name="ContentSearch.ComputedFields.ParallelIndexing.Enabled" set:value="false" />
    </settings>
  </sitecore>
</configuration>

Note: This approach does not require code changes. It does not affect other levels of parallel indexing. This approach might increase index update/rebuild time as computed fields will be added sequentially.

Option 2

Use the SecurityDisabler and SiteContextSwitcher classes to set correct context values.

using Sitecore.Configuration;
using Sitecore.SecurityModel;
using Sitecore.Sites;
...
public override object ComputeFieldValue(IIndexable indexable)
{            
   using (new SecurityDisabler())
   {
       using (new SiteContextSwitcher(new SiteContext(Factory.GetSiteInfo("shell"))))
       {
           //logic of the custom computed index field
       }
   }
}

Note:This approach requires access to the source code of the affected fields. It prevents the issue without slowing down the indexing process.

Useful links

Information about a similar issue related to field-level language fallback can be found at KB0021800.