Pages

07 December, 2021

Sitecore PowerShell - Get All Sitecore Users With Basic Properties

Saving the handy script to get all the Sitecore Users with basic properties like Is Admin, Is locked out, email address etc. 



07 October, 2021

Sitecore 9, 10 - Experience Editor Slow or Hang in general or for non-English languages?

As part of the Sitecore Upgrade to Sitecore 10.0.1, we faced an issue related to experience editor. When we try to edit the page in experience editor for non-english version of the item, the CM website hangs and then it will just block every other requests. Entire CM instance will be unavailable. 

Troubleshooting:

  1. Checked the Vanilla Sitecore 10.0.1 version and experience editor is working as expected. 
  2. Debugged the solution and found out that Dictionary API (Sitecore.Globalization.Translate.Text) is the root cause for the slowness. 
Solution:
Sitecore has reported a similar issue as a known issue for Sitecore 9.3 onwards and the fix was included in Sitecore 10.1.0. Sitecore article has a fix for version 9.3 in their page

Reached out to Sitecore to get the fix for Sitecore 10.0.1 version. For this version, the hotfix has a set of DLLs and a config file. They are not support DLLs. So we should include this as part of the CI/CD pipeline so that it does not get overwritten next time. 

After applying the fix, the experience editor started to respond for all the other languages as well. 

Reach out to Sitecore if your Sitecore version (9.3 to 10.0.1) has a similar issue on experience editor and they will be providing the hotfix for the particular version. 

17 September, 2021

Sitecore PowerShell - Create a report with all referenced items by Lookup Items

In case if you have a list of lookup items and you would like to get a Sitecore PowerShell report of all the referenced items in Sitecore, you can make use of the below script. Also this script demonstrates the usage of PSObject by which you can create custom object and render it in the output window. This approach is using Link database and rebuilding the link database helps you to get the most accurate results. 

With PSObject, you can merge two different object and create a new custom object which can be used for rendering the results. Instead of using multi-dimensional arrays, this can be a better approach. 




02 September, 2021

Sitecore Upgrade - Codebase Upgrade - Migrate from packages.config to PackageReference

We have been always using packages.config file to manage the nuget package references. Instead of config file, PackageReference has been introduced to provide benefits for the developers. 

Benefits:

  1. Instead of showing all the dependencies in the packages.config file, only top level dependencies will be added as part of PackageReference. This gives a clean and simple view on the references. 
  2. Ability to manage all the project level configuration like package references in a single csproj file itself.
  3. Adding and removing packages are faster compared to Packages.config file. 
Migration of Packages.config to PackageReferences
To migration all the existing references, right-click the References node in Solution Explorer, and select the Migrate packages.config to PackageReference command.


Default to PackageReferences:
In order to add packages to PackageReferences by default, open Tools > NuGet Package Manager > Package Manager Settings menu, change the Default package management format to PackageReference.



20 August, 2021

Sitecore Upgrade - Codebase Upgrade - Migrate to SDK Project Format

The older style of csproj has lot of cumbersome tasks like adding files, excluding files, complex in adding references and packages.config file maintenance. 

The new SDK project format was introduced along with Visual Studio 2017. Some of the pros includes:

  • Clean csproj file with the ability to modify the .NET framework or .NET core version
  • Ability to view/edit the csproj file without excluding the project in Visual Studio
  • No need of Packages.json file and include the nuget references as part of csproj file itself
  • No need to include each and every .cs file to the project. 
A typical old csproj format file: You will see so many lines which could have been defaulted somewhere else. 
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\build\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props" Condition="Exists('..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\build\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props')" />
  <Import Project="..\..\..\packages\Microsoft.Net.Compilers.1.0.0\build\Microsoft.Net.Compilers.props" Condition="Exists('..\..\..\packages\Microsoft.Net.Compilers.1.0.0\build\Microsoft.Net.Compilers.props')" />
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProductVersion>
    </ProductVersion>
    <SchemaVersion>2.0</SchemaVersion>
    <ProjectGuid>{30EB7022-CCB9-48AB-96C1-3556565A51C1}</ProjectGuid>
    <ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>SitecoreDemo.Feature.Accounts</RootNamespace>
    <AssemblyName>SitecoreDemo.Feature.Accounts</AssemblyName>
    <TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
    <UseIISExpress>true</UseIISExpress>
    <IISExpressSSLPort />
    <IISExpressAnonymousAuthentication />
    <IISExpressWindowsAuthentication />
    <IISExpressUseClassicPipelineMode />
    <UseGlobalApplicationHostFile />
    <SccProjectName>SAK</SccProjectName>
    <SccLocalPath>SAK</SccLocalPath>
    <SccAuxPath>SAK</SccAuxPath>
    <SccProvider>SAK</SccProvider>
    <NuGetPackageImportStamp>
    </NuGetPackageImportStamp>
    <Use64BitIISExpress />
    <TargetFrameworkProfile />
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="Microsoft.AI.Agent.Intercept, Version=1.2.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
      <HintPath>..\..\..\packages\Microsoft.ApplicationInsights.Agent.Intercept.1.2.1\lib\net45\Microsoft.AI.Agent.Intercept.dll</HintPath>
      <Private>True</Private>
    </Reference>
    <Reference Include="Microsoft.AI.DependencyCollector, Version=2.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
      <HintPath>..\..\..\packages\Microsoft.ApplicationInsights.DependencyCollector.2.1.0\lib\net45\Microsoft.AI.DependencyCollector.dll</HintPath>
      <Private>True</Private>
    </Reference>
    <Reference Include="Microsoft.AI.PerfCounterCollector, Version=2.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
      <HintPath>..\..\..\packages\Microsoft.ApplicationInsights.PerfCounterCollector.2.1.0\lib\net45\Microsoft.AI.PerfCounterCollector.dll</HintPath>
      <Private>True</Private>
    </Reference>
    <Reference Include="Microsoft.AI.ServerTelemetryChannel, Version=2.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
      <HintPath>..\..\..\packages\Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel.2.1.0\lib\net45\Microsoft.AI.ServerTelemetryChannel.dll</HintPath>
      <Private>True</Private>
    </Reference>
    <Reference Include="Microsoft.AI.Web, Version=2.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
      <HintPath>..\..\..\packages\Microsoft.ApplicationInsights.Web.2.1.0\lib\net45\Microsoft.AI.Web.dll</HintPath>
      <Private>True</Private>
    </Reference>
    <Reference Include="Microsoft.AI.WindowsServer, Version=2.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
      <HintPath>..\..\..\packages\Microsoft.ApplicationInsights.WindowsServer.2.1.0\lib\net45\Microsoft.AI.WindowsServer.dll</HintPath>
      <Private>True</Private>
    </Reference>
    <Reference Include="Microsoft.ApplicationInsights, Version=2.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
      <HintPath>..\..\..\packages\Microsoft.ApplicationInsights.2.1.0\lib\net46\Microsoft.ApplicationInsights.dll</HintPath>
      <Private>True</Private>
    </Reference>
    <Reference Include="Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
      <HintPath>..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll</HintPath>
      <Private>True</Private>
    </Reference>
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
      <HintPath>..\..\..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
      <Private>True</Private>
    </Reference>
    <Reference Include="RestSharp, Version=105.2.3.0, Culture=neutral, processorArchitecture=MSIL">
      <SpecificVersion>False</SpecificVersion>
      <HintPath>..\..\..\packages\RestSharp.105.2.3\lib\net46\RestSharp.dll</HintPath>
    </Reference>
    <Reference Include="System.Net.Http" />
    <Reference Include="System.Runtime.Serialization" />
    <Reference Include="System.Web.DynamicData" />
    <Reference Include="System.Web.Entity" />
    <Reference Include="System.Web.ApplicationServices" />
    <Reference Include="System.ComponentModel.DataAnnotations" />
    <Reference Include="System" />
    <Reference Include="System.Data" />
    <Reference Include="System.Core" />
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="System.Web.Extensions" />
    <Reference Include="System.Xml.Linq" />
    <Reference Include="System.Drawing" />
    <Reference Include="System.Web" />
    <Reference Include="System.Xml" />
    <Reference Include="System.Configuration" />
    <Reference Include="System.Web.Services" />
    <Reference Include="System.EnterpriseServices" />
  </ItemGroup>
  <ItemGroup>
    <Reference Include="System.Web.Razor">
      <HintPath>..\..\..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll</HintPath>
    </Reference>
    <Reference Include="System.Web.Webpages">
      <HintPath>..\..\..\packages\Microsoft.AspNet.Webpages.3.2.3\lib\net45\System.Web.Webpages.dll</HintPath>
    </Reference>
    <Reference Include="System.Web.Webpages.Deployment">
      <HintPath>..\..\..\packages\Microsoft.AspNet.Webpages.3.2.3\lib\net45\System.Web.Webpages.Deployment.dll</HintPath>
    </Reference>
    <Reference Include="System.Web.Webpages.Razor">
      <HintPath>..\..\..\packages\Microsoft.AspNet.Webpages.3.2.3\lib\net45\System.Web.Webpages.Razor.dll</HintPath>
    </Reference>
    <Reference Include="System.Web.Helpers">
      <HintPath>..\..\..\packages\Microsoft.AspNet.Webpages.3.2.3\lib\net45\System.Web.Helpers.dll</HintPath>
    </Reference>
    <Reference Include="Microsoft.Web.Infrastructure">
      <HintPath>..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
    </Reference>
    <Reference Include="System.Web.Mvc">
      <HintPath>..\..\..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll</HintPath>
    </Reference>
  </ItemGroup>
  <ItemGroup>
    <Content Include="Views\ChangePassword\_ChangePassword.cshtml" />
    <Content Include="Views\ChangePassword\_ChangePasswordEdit.cshtml" />
    <Content Include="Views\Common\_SiteDownAlert.cshtml" />    
    <Content Include="Views\Common\_WelcomeBanner.cshtml" />
    <Content Include="Views\Notification\Preference.cshtml" />
    <Content Include="Views\Notification\UserInfo.cshtml" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Attribute\SessionExpireFilterAttribute.cs" />    
    <Compile Include="BusinessLogic\ChangePassword.cs" />
    <Compile Include="Controllers\ChangePasswordController.cs" />
    <Compile Include="Constants.cs" />
    <Compile Include="Controllers\BaseController.cs" />
    <Compile Include="Controllers\NotificationController.cs" />
    <Compile Include="Controllers\ToolsController.cs" />
    <Compile Include="Helper\EnumHelper.cs" />
    <Compile Include="Models\Customer.cs" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\Marketing\Marketing.csproj">
      <Project>{1117786e-0ae1-44b0-af00-1ec3adc173ee}</Project>
      <Name>Marketing</Name>
    </ProjectReference>
  </ItemGroup>
  <ItemGroup>
    <Content Include="web.config" />
    <None Include="web.Debug.config">
      <DependentUpon>web.config</DependentUpon>
    </None>
  </ItemGroup>
  <PropertyGroup>
    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'DEV|AnyCPU'">
    <OutputPath>bin\</OutputPath>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'PROD|AnyCPU'">
    <OutputPath>bin\</OutputPath>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'UAT|AnyCPU'">
    <OutputPath>bin\</OutputPath>
  </PropertyGroup>
  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
  <Import Project="$(VSToolsPath)\WebApplications\Microsoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
  <ProjectExtensions>
    <VisualStudio>
      <FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
        <WebProjectProperties>
          <UseIIS>False</UseIIS>
          <AutoAssignPort>True</AutoAssignPort>
          <DevelopmentServerPort>58420</DevelopmentServerPort>
          <DevelopmentServerVPath>/</DevelopmentServerVPath>
          <IISUrl>http://localhost:57567/</IISUrl>
          <NTLMAuthentication>False</NTLMAuthentication>
          <UseCustomServer>False</UseCustomServer>
          <CustomServerUrl>
          </CustomServerUrl>
          <SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
        </WebProjectProperties>
      </FlavorProperties>
    </VisualStudio>
  </ProjectExtensions>
  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
    <PropertyGroup>
      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
    </PropertyGroup>
    <Error Condition="!Exists('..\..\..\packages\Microsoft.Net.Compilers.1.0.0\build\Microsoft.Net.Compilers.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.Net.Compilers.1.0.0\build\Microsoft.Net.Compilers.props'))" />
    <Error Condition="!Exists('..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\build\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\build\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.props'))" />
  </Target>
  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
       Other similar extension points exist, see Microsoft.Common.targets.
  <Target Name="BeforeBuild">
  </Target>
  <Target Name="AfterBuild">
  </Target>
  -->
</Project>

Migrated to SDK format: A simple SDL format csproj file. Readable and easily modifiable. 
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net48</TargetFramework>
	<ApplicationIcon />
	<OutputType>Library</OutputType>
	<StartupObject />
	<Authors>Author</Authors>
	<Company>Company Name</Company>
	<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
	<CodeAnalysisRuleSet>$(SolutionDir)\StyleCop.ruleset</CodeAnalysisRuleSet>
  </PropertyGroup> 
  <ItemGroup>
    <Content Include="Views\ChangePassword\_ChangePassword.cshtml" />
    <Content Include="Views\ChangePassword\_ChangePasswordEdit.cshtml" />
    <Content Include="Views\Common\_SiteDownAlert.cshtml" />    
    <Content Include="Views\Common\_WelcomeBanner.cshtml" />
    <Content Include="Views\Notification\Preference.cshtml" />
    <Content Include="Views\Notification\UserInfo.cshtml" />
    <Content Include="Web.config" />
  </ItemGroup>
  <ItemGroup>
    <PackageReference Include="Glass.Mapper.Sc.93.Core">
      <Version>5.6.160</Version>
    </PackageReference>
    <PackageReference Include="Sitecore.Mvc" Version="9.3.0" />
    <PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
    <PackageReference Include="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" Version="3.6.0" />
    <PackageReference Include="Sitecore.Kernel" Version="9.3.0" />
    <PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
  </ItemGroup>
  <ItemGroup>
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System" />
  </ItemGroup>
  <ItemGroup>
    <Folder Include="Models\ExtensionModels\" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\..\..\Foundation\Extensions\website\SitecoreDemo.Foundation.Extensions.csproj">
      <Project>{a53176ca-ff2g-4b2s-h6j3-1tfs2g94jfb5}</Project>
      <Name>SitecoreDemo.Foundation.Extensions</Name>
    </ProjectReference>
    <ProjectReference Include="..\..\..\Foundation\Marketing\website\SitecoreDemo.Foundation.Marketing.csproj" />
  </ItemGroup>
 </Project>

How to migrate:
There are few options available to migrate to SDK format.

Option 1:
An open source module which does most of the task for us. By simply calling the console app followed by our csproj file will convert most of the project files. We may need to clean up few reference related tasks which will discuss in the next post of the Upgrade series. 


Option 2:
Manually change the csproj file to SDK format. 
  1. Replace entire PropertyGroup with the simple SDK version.
    1. TargetFramework
    2. OutputType
    3. GenerateAssemblyInfo
  2. Remove all compiler related <Import />
  3. Remove all <ItemGroup /> containing .cs files
  4. Remove <ProjectExtensions /> and <Target />
Migrating from packages.json to PackageReferences will be explained in the next blog post. 

18 August, 2021

Sitecore Upgrade - Codebase Upgrade Series - Framework upgrade - .NET

As part of the Sitecore codebase upgrade series, in this blog, we are going to deal with upgrading .NET Framework version. 

Option 1: Using PowerShell, we can quickly update the version in all the csproj files. The script has been added in this blog. This script will update both legacy and SDK project format.

Option 2: To upgrade .NET framework, you can open the csproj files in Notepad++ and replace the version number from 4.x to 4.8 (or desired version as per Sitecore). 

  • SDK Style Projects
    Should replace <TargetFramework>net4xx</TargetFramework> with the targeted version. 
  • Legacy Style Projects
    Should replace <TargetFrameworkVersion>v4.x.x</TargetFrameworkVersion> with the targeted version. 

Option 3: There is a Visual Studio marketplace module called TargetFrameworkMigrator. Once you install it, you can change the target framework to the desired version. This will work only for the Legacy Style Projects. SDK Style Project support will be added in the next version as per the roadmap. 

  • Once you install the VS Extension. Open the extension from Tools menu --> Target Framework Migrator.
  • Choose the projects you want to migrate, then click Migrate. 


17 August, 2021

Update .NET Version in SDK and Legacy Project Format Type

As part of Sitecore Upgrade, we had to upgrade .NET version in 100+ Helix projects. The below script was used to update the version in the projects quickly. 

Since Microsoft introduced SDK project format, the XML tag in the project file and also the version format are different. The below updates .NET Target Framework version in both SDK and Legacy Project format types. 


22 July, 2021

Coveo for Sitecore 5 with Sitecore Horizon 10

When we try to use Sitecore Horizon (10.0.1) with with a solution having Coveo integration, Sitecore Horizon throws the below exception in the UI. It does not load any sites or languages in the dropdown. When we try to remove site definition with name "coveo_website", it is loading fine. As per Coveo, we should not remove this site definition as it will impact Coveo integration. 

Reached out to awesome Sitecore community in Sitecore Slack for help and Jeff (@jflh) provided a simple workaround patch configuration in the Sitecore.Demo.Platform repo. Basically we are changing the Coveo_website site definition to an item that does not exist. Horizon will not consider this site as a valid site to be editable in the editor. 

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:coveo="http://www.sitecore.net/xmlconfig/coveo/">
	<sitecore coveo:require="!disabled">
		<sites>
			<!--
				DEMO WORKAROUND
				Coveo for Sitecore and Horizon modules are incompatible by default. Horizon handles the coveo_website as a content site.
				We are applying a workaround similar to what Unicorn had done to fix the same issue: https://github.com/SitecoreUnicorn/Unicorn/issues/398
				We change the coveo_website rootPath to an item that does not exist.
			-->
			<site name="coveo_website">
				<patch:attribute name="rootPath" value="/coveo/for/sitecore/module" />
			</site>
		</sites>
	</sitecore>
</configuration>

After adding this configuration patch, Horizon started to load our sites with Coveo_website site. 

Sitecore Slack Chat: https://sitecorechat.slack.com/archives/C0CF16R9C/p1626812378104900

20 July, 2021

Coveo for Sitecore Upgrade - HtmlContentInBodyWithRequestsProcessor to FetchPageContentProcessor - Length cannot be less than zero

After upgrading from Coveo for Sitecore 4 to version 5, it is noted that there is a new processor which replaces the old HtmlContentInBodyWithRequestsProcessor. New processor in Coveo 5 is called as FetchPageContentProcessor. Similar to the previous processor, it executes an HTTP request, get the page response and then sends the data to the Coveo cloud. Enabling this processor delays the indexing. 

In Coveo 4 for Sitecore

<configuration xmlns:x="http://www.sitecore.net/xmlconfig/" 
  xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:coveo="http://www.sitecore.net/xmlconfig/coveo/">
  <sitecore coveo:require="!disabled">
    <pipelines>
      <coveoPostItemProcessingPipeline>
        <processor type="Coveo.SearchProvider.Processors.HtmlContentInBodyWithRequestsProcessor, Coveo.SearchProviderBase">
          <StartCommentText>BEGIN NOINDEX</StartCommentText>
          <EndCommentText>END NOINDEX</EndCommentText>
        </processor>
      </coveoPostItemProcessingPipeline>
    </pipelines>
  </sitecore>
</configuration>

In Coveo 5 for Sitecore (recommended by Coveo)

<coveoPostItemProcessingPipeline>
  <processor type="Coveo.SearchProvider.Processors.ExecuteGetBinaryDataPipeline, Coveo.SearchProviderBase" />
</coveoPostItemProcessingPipeline>
<coveoGetBinaryData>
  <processor type="Coveo.SearchProvider.Processors.FetchPageContentProcessor, Coveo.SearchProviderBase">
    <inboundFilter hint="list:AddInboundFilter">
      <itemsWithLayout type="Coveo.SearchProvider.Processors.FetchPageContent.Filters.ItemsWithLayout, Coveo.SearchProviderBase" />
    </inboundFilter>
    <preAuthentication hint="list:AddPreAuthenticator" />
    <postProcessing hint="list:AddPostProcessing">
      <processor type="Coveo.SearchProvider.Processors.FetchPageContent.PostProcessing.CleanHtml, Coveo.SearchProviderBase">
        <startComment>BEGIN NOINDEX</startComment>
        <endComment>END NOINDEX</endComment>
      </processor>
    </postProcessing>
  </processor>
</coveoGetBinaryData>

In Coveo 5, there is a post processing processor called CleanHtml which will be executed on the fetched content after the HTTP request. This processor helps you to guide Coveo to index only a certain section of your web page. 

For an example, if you want to remove header, footer, navigation from the index document, you can mark the section using Start Comment and End Comment. In this configuration, it will be <!-- BEGIN NOINDEX --> and <!-- END NOINDEX -->

In a Sitecore instance with Coveo 4, we had nested comments as below. Coveo indexing with the HtmlContentInBodyWithRequestsProcessor processor were able to handle the nested comments and remove the section and send the HTML content to Coveo. 

<!-- BEGIN NOINDEX -->
    <!-- BEGIN NOINDEX -->
    	Content 1
    <!-- END NOINDEX -->
    <!-- BEGIN NOINDEX -->
    	Content 2
    <!-- END NOINDEX -->
<!-- END NOINDEX -->

In Coveo 5, the new processor CleanHtml throws below exception if there is a nested comments. I have even decompiled both the processor and tested the output of the HTML with nested comments and CleanHtml processor throws exception while removing content. 

ManagedPoolThread #19 02:19:52 ERROR An error occurred while trying to clean the HTML, no cleaning will be done.
Exception: System.ArgumentOutOfRangeException
Message: Length cannot be less than zero.
Parameter name: length
Source: mscorlib
   at System.String.Substring(Int32 startIndex, Int32 length)
   at Coveo.SearchProvider.Utils.HtmlCleaner.CleanHtmlContent(String p_HtmlContent, String p_StartCommentText, String p_EndCommentText)
   at Coveo.SearchProvider.Processors.HtmlContentInBodyWithRequestsProcessor.CollectHttpWebResponsesForAllClickableUris(List`1 p_CoveoIndexableItems, Dictionary`2 p_CleanedBinaryDataByUri)

We do not see a way to prevent this error when having a nested comments. When overriding the CleanHtml processor with the old processor method which cleans the HTML, it works but I do not think it is a good way to use the old code and patch it with the new processor. Raised a Coveo ticket to see if there is any workaround. 

Update: As per Coveo, there is no workaround in the Sitecore side, nested tags will need to be removed. 

  1. Jeff (@jflh) suggested that we could use a custom processor which cleans the HTML based on CSS selector instead of CleanHtml processor.
  2. He also provided a suggestion to use a Chrome extension which can help you to decide the Html elements to clean by the processor.Very useful. 
  3. Coveo has an Indexing Pipeline Extension (IPE) which works in the same fashion as mentioned in the first point (custom processor). This requires us to remove all BEGIN and END NOINDEX tags. We need to add a custom class coveo-no-index and IPE will select those sections and remove it. 

Sitecore Slack Chathttps://sitecorechat.slack.com/archives/C0CF16R9C/p1626979876116500

Reference

  1. Index Page Content With the FetchPageContentProcessor
  2. Nested NOINDEX tags preventing HTML content from being fetched during indexing

18 July, 2021

Sitecore Solr - multiple values encountered for non multiValued field

In case if you have faced an error "multiple values encountered for non multiValued field" in Solr, you will need to find the fieldType element in the Sitecore Solr Index Configuration and set it as stringCollection in returnType.

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <contentSearch>
      <indexConfigurations>
        <defaultSolrIndexConfiguration type="Sitecore.ContentSearch.SolrProvider.SolrIndexConfiguration, Sitecore.ContentSearch.SolrProvider">
          <fieldMap ref="contentSearch/indexConfigurations/defaultSolrIndexConfiguration/fieldMap">
            <fieldNames hint="raw:AddFieldByFieldName">
              <fieldType fieldName="tags" returnType="stringCollection"/>
            </fieldNames>
          </fieldMap>
        </defaultSolrIndexConfiguration>
      </indexConfigurations>
    </contentSearch>
  </sitecore>
</configuration>

Error:

org.apache.solr.common.SolrException: ERROR: [doc=sitecore://master/{37ac1cc6-109b-41ee-9f94-3f527ff22c12}?lang=en&ver=1&ndx=sitecore_master_index] multiple values encountered for non multiValued field tags_t: [594396e563f046b98418b3a8a52d4aa2, 5e918d1e4412450298a8eae0ee65da65, 9fe55245aa6641b79ae55cd47874ee0e]
	at org.apache.solr.update.DocumentBuilder.toDocument(DocumentBuilder.java:153)
	at org.apache.solr.update.AddUpdateCommand.getLuceneDocument(AddUpdateCommand.java:109)
	at org.apache.solr.update.DirectUpdateHandler2.updateDocOrDocValues(DirectUpdateHandler2.java:975)
	at org.apache.solr.update.DirectUpdateHandler2.doNormalUpdate(DirectUpdateHandler2.java:345)
	at org.apache.solr.update.DirectUpdateHandler2.addDoc0(DirectUpdateHandler2.java:292)
	at org.apache.solr.update.DirectUpdateHandler2.addDoc(DirectUpdateHandler2.java:239)
	at org.apache.solr.update.processor.RunUpdateProcessor.processAdd(RunUpdateProcessorFactory.java:76)
	at org.apache.solr.update.processor.UpdateRequestProcessor.processAdd(UpdateRequestProcessor.java:55)
	at org.apache.solr.update.processor.DistributedUpdateProcessor.doLocalAdd(DistributedUpdateProcessor.java:259)
	at org.apache.solr.update.processor.DistributedUpdateProcessor.doVersionAdd(DistributedUpdateProcessor.java:489)
	at org.apache.solr.update.processor.DistributedUpdateProcessor.lambda$versionAdd$0(DistributedUpdateProcessor.java:339)
	at org.apache.solr.update.VersionBucket.runWithLock(VersionBucket.java:50)
	at org.apache.solr.update.processor.DistributedUpdateProcessor.versionAdd(DistributedUpdateProcessor.java:339)
	at org.apache.solr.update.processor.DistributedUpdateProcessor.processAdd(DistributedUpdateProcessor.java:225)
	at org.apache.solr.update.processor.LogUpdateProcessorFactory$LogUpdateProcessor.processAdd(LogUpdateProcessorFactory.java:103)
	at org.apache.solr.handler.loader.XMLLoader.processUpdate(XMLLoader.java:261)
	at org.apache.solr.handler.loader.XMLLoader.load(XMLLoader.java:188)
	at org.apache.solr.handler.UpdateRequestHandler$1.load(UpdateRequestHandler.java:97)
	at org.apache.solr.handler.ContentStreamHandlerBase.handleRequestBody(ContentStreamHandlerBase.java:68)
	at org.apache.solr.handler.RequestHandlerBase.handleRequest(RequestHandlerBase.java:211)
	at org.apache.solr.core.SolrCore.execute(SolrCore.java:2596)
	at org.apache.solr.servlet.HttpSolrCall.execute(HttpSolrCall.java:799)
	at org.apache.solr.servlet.HttpSolrCall.call(HttpSolrCall.java:578)
	at org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:419)
	at org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:351)
	at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1602)
	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:540)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:146)
	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:548)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:257)
	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1711)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255)
	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1347)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203)
	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:480)
	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1678)
	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201)
	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1249)
	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144)
	at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:220)
	at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:152)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
	at org.eclipse.jetty.rewrite.handler.RewriteHandler.handle(RewriteHandler.java:335)
	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
	at org.eclipse.jetty.server.Server.handle(Server.java:505)
	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:370)
	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:267)
	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305)
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
	at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.onFillable(SslConnection.java:427)
	at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:321)
	at org.eclipse.jetty.io.ssl.SslConnection$2.succeeded(SslConnection.java:159)
	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
	at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:117)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:333)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:310)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:168)
	at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:126)
	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:366)
	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:781)
	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:917)
	at java.base/java.lang.Thread.run(Thread.java:829)

16 July, 2021

Coveo for Sitecore Upgrade - Sitecore Item Fields missing in Index Documents

When we recently upgraded Coveo for Sitecore to version 5, we noticed certain fields used in the result template are no longer available in Coveo Index Documents. Due to that, we had different and incorrect search results in the webpage. 

It has been decided by Coveo in October 2018 that they no longer index certain Sitecore fields to Coveo Cloud to reduce the payload. Some of these fields are standard fields to run a query. Some of the important fields which we were missing in index: templateid, templatename, displayname, name, title.

Two solutions provided by Coveo:

  1. Referencing an alternate field instead
  2. Adding the legacy metadata into the documents programmatically

Coveo provided an article with a pipeline to index those (legacy) fields. With the addition of the pipeline, the payload of each document will be much higher and it can slow down your indexing time. Make sure to review the required fields and add only those fields in the indexes. 

You can refer the Coveo documentation to get hold the pipeline code and customize it based on your requirement. 

Reference: https://docs.coveo.com/en/2699/coveo-for-sitecore-v4/field-is-no-longer-indexed-in-the-sitecore-items

15 July, 2021

Coveo for Sitecore 5 - Steps to follow after restoring Sitecore master database

There are instances when we get the backup of Production database and restore it in development environment to troubleshoot peculiar issues or to update the latest content. In those cases, if we have Coveo for Sitecore, after we restore the Sitecore master database, the linking between your Sitecore instance and Coveo cloud breaks, decryption key become invalid and you will need to link it again. 

After you restore the master database, you may be getting following errors in the Sitecore log. 

13528 13:34:32 WARN  An error occurred while decrypting the SitecorePassword configuration element value. The element value will be used as is assuming it is unencrypted. You can encrypt this password by using the Coveo Command Center at /coveo/command-center/index.html#configuration.
Exception: System.Security.Cryptography.CryptographicException
Message: Padding is invalid and cannot be removed.
Source: mscorlib
   at System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast)
   at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
   at System.Security.Cryptography.CryptoStream.FlushFinalBlock()
   at System.Security.Cryptography.CryptoStream.Dispose(Boolean disposing)
   at System.IO.Stream.Close()
   at Coveo.Framework.Encryption.RijndaelEncrypter.DecryptData(Byte[] p_DataToDecrypt)
   at Coveo.Framework.Security.ConfigurationValueEncrypter.Decrypt(String p_EncryptedValue)
   at Coveo.Framework.Security.ConfigurationValueEncrypter.SafeDecrypt(String p_EncryptedValue, String p_WarnMessage)

13528 13:34:32 WARN  An error occurred while decrypting the SitecorePassword configuration element value. The element value will be used as is assuming it is unencrypted. You can encrypt this password by using the Coveo Command Center at /coveo/command-center/index.html#configuration.
Exception: System.Security.Cryptography.CryptographicException
Message: Padding is invalid and cannot be removed.
Source: mscorlib
   at System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast)
   at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount)
   at System.Security.Cryptography.CryptoStream.FlushFinalBlock()
   at System.Security.Cryptography.CryptoStream.Dispose(Boolean disposing)
   at System.IO.Stream.Close()
   at Coveo.Framework.Encryption.RijndaelEncrypter.DecryptData(Byte[] p_DataToDecrypt)
   at Coveo.Framework.Security.ConfigurationValueEncrypter.Decrypt(String p_EncryptedValue)
   at Coveo.Framework.Security.ConfigurationValueEncrypter.SafeDecrypt(String p_EncryptedValue, String p_WarnMessage)


ManagedPoolThread #1 13:35:34 ERROR An error while Initializing occurred
Exception: Coveo.Framework.Exceptions.CoveoIndexConfigurationException
Message: There was an error in the Coveo Index Configuration.: Either the SitecoreUsername or SitecorePassword configuration value is invalid. Please enter valid credentials.
Source: Coveo.Framework
   at Coveo.Framework.Configuration.CoveoIndexConfiguration.ValidateSitecoreCredentials()
   at Coveo.Framework.Configuration.CoveoIndexConfiguration.Validate()
   at Coveo.SearchProvider.ProviderIndexBase.Initialize()


ManagedPoolThread #1 13:35:34 WARN  Precondition failed: The parameter 'p_Communication' must not be null
ManagedPoolThread #1 13:35:34 ERROR Exception
Exception: System.Reflection.TargetInvocationException
Message: Exception has been thrown by the target of an invocation.
Source: mscorlib
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Sitecore.Reflection.ReflectionUtil.InvokeMethod(MethodInfo method, Object[] parameters, Object obj)
   at Sitecore.Jobs.JobRunner.RunMethod(JobArgs args)
   at (Object , Object )
   at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
   at Sitecore.Pipelines.DefaultCorePipelineManager.Run(String pipelineName, PipelineArgs args, String pipelineDomain, Boolean failIfNotExists)
   at Sitecore.Pipelines.DefaultCorePipelineManager.Run(String pipelineName, PipelineArgs args, String pipelineDomain)
   at Sitecore.Jobs.DefaultJob.DoExecute()
   at Sitecore.Abstractions.BaseJob.ThreadEntry(Object state)

Nested Exception

Exception: System.ArgumentNullException
Message: Precondition failed: The parameter 'p_Communication' must not be null
Parameter name: p_Communication
Source: Coveo.Framework
   at Coveo.Framework.CNL.Precondition.NotNull(Object p_Parameter, String p_ParameterName)
   at Coveo.SearchProvider.AbstractProviderUpdateContext..ctor(ISearchIndexSummary p_IndexSummary, IIndexCommunication p_Communication)
   at Coveo.SearchProvider.ProviderUpdateContext..ctor(ISearchIndex p_Index, IIndexCommunication p_Communication)
   at Coveo.SearchProvider.ProviderIndex.CreateUpdateContext()
   at Coveo.SearchProvider.ProviderIndex.Update(IEnumerable`1 p_IndexableInfo)

In order to link the connection, you will need to use Coveo Configuration page and follow the steps.

  1. Go to Sitecore Control Panel -> Coveo Search --> Configuration Manager
  2. Click Login. You will be redirected to Coveo Cloud login. After login, you may need to grant access by clicking Authorize button.


  3. Make sure proper Organization is selected and click Apply and Restart.


  4. Once the Sitecore instance restarts, there is a high chance that user account configured to connect to Sitecore may be locked. You can go to Sitecore User Manager, select that user and unlock it. 
  5. Once it is unlocked or if it is not locked, then you can go Coveo Search --> Configuration Manager --> Security --> Enter the password for the configured user and click Apply and Restart. If there is a success message, then it is working fine and Sitecore instance will restart. And you will be able to see all the indexes and fields in the Coveo Admin page. 

14 July, 2021

Sitecore Upgrade - Redis Session State crashes IIS App Pool

After upgrading Sitecore 9.0.1 to 10.0.1, I enabled the Redis Cache Session State for Content Delivery environment. App pool started to crash whenever the session ends. As part of SessionEnd, all the analytics session data will be pushed to xDB. At that time, there is an exception at the background thread and crashes the app pool. After multiple crashes, app pool stopped as well. 

ERROR Unhandled exception detected. The ASP.NET worker process will be terminated. 
Exception: System.Reflection.TargetInvocationException
Message: Exception has been thrown by the target of an invocation.
Source: mscorlib
   at System.RuntimeMethodHandle.SerializationInvoke(IRuntimeMethodInfo method, Object target, SerializationInfo info, StreamingContext& context)
   at System.Runtime.Serialization.ObjectManager.CompleteISerializableObject(Object obj, SerializationInfo info, StreamingContext context)
   at System.Runtime.Serialization.ObjectManager.FixupSpecialObject(ObjectHolder holder)
   at System.Runtime.Serialization.ObjectManager.DoFixups()
   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at Sitecore.SessionProvider.Redis.BinarySerializer.Deserialize(Byte[] dataAsBytes)
   at Sitecore.SessionProvider.Redis.ChangeTrackingSessionStateItemCollection.GetData(String normalizedName)
   at System.Web.Util.AspCompatApplicationStep.AnyStaObjectsInSessionState(HttpSessionState session)
   at System.Web.HttpApplicationFactory.FireSessionOnEnd(HttpSessionState session, Object eventSource, EventArgs eventArgs)
   at System.Web.SessionState.SessionOnEndTargetWorkItem.RaiseOnEndCallback()
   at System.Web.Util.WorkItem.CallCallbackWithAssert(WorkItemCallback callback)
   at System.Web.Util.WorkItem.OnQueueUserWorkItemCompletion(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
   at System.Threading.ThreadPoolWorkQueue.Dispatch()

Nested Exception

Exception: System.Runtime.Serialization.SerializationException
Message: Member 'f' was not found.
Source: mscorlib
   at System.Runtime.Serialization.SerializationInfo.GetElement(String name, Type& foundType)
   at System.Runtime.Serialization.SerializationInfo.GetByte(String name)
   at Sitecore.Analytics.Tracking.SessionSettings..ctor(SerializationInfo info, StreamingContext context)

One of the key part of the upgrade documentation is the post deployment steps. In that it is mentioned that we should clear the session state. Also it means that we should not use the same Redis Cache server for both the Sitecore version as it can cause conflict. We were trying to use the same Redis Cache server and once we brought in a new Redis Cache server dedicated for the new Sitecore environment, everything started to work without any crashes. Or You should clear the session data on an existing Redis Cache server and use it only for the new Sitecore version.

  • Clear the Session data before loading the upgraded site or
  • Configure a new dedicated Redis Cache Server

29 June, 2021

Sitecore Marketing Automation Engine fails to start - Possibly Certificate Access Issue

If the Sitecore Marketing Automation Engine service fails to start after the installation, then most of them time, it must be due to certificate access issue. 

If your application pool is using a dedicated service account, then take a note of the service account name. 

If the application pool is configured with ApplicationPoolIdentity, then you can get the IIS Website name for each role. For example, if the IIS Website name is sc101.local.cm, then ApplicationPoolIdentity will be "IIS AppPool\sc101.local.cm". 

Once you have got the name of the account, then

  • Select Run from the Start menu, and then enter certlm.msc
  • Under Certificates - Local Computer in the left pane, expand the directory Personal - Certificates.
  • Choose xConnect Certificate, Right Click - All Tasks - Manage Private Keys.
  • In the Permission window, click Add and paste the account name and Apply.


     

25 June, 2021

Sitecore Upgrade - Transferred Sitecore Membership User Password does not work - Possible Reasons

In case if you have migrated the password using Sitecore utility as mentioned here, your migrated password may not work. Some of the steps which are mentioned below may help. 

  1. Check whether the script ran successfully on the current server
    You may need to confirm whether the source and destination server used to migrate the password is correct and also whether the destination server has all the users and password. 

  2. Check the Membership Password hashAlgorithmType
    You may need to check whether the hashAlgorithmType is same in the source and the destination Sitecore instance. You can view it in the web.config file in <membership> node. Attribute name is hashAlgorithmType. For the migrated password to work, destination hashAlgorithmType should be same as source hashAlgorithmType. 

  3. Migration to Sitecore 9.2 with Identity Provider
    In case if the destination server is going to use Siteore Identity Provider to authenticate the Sitecore membership users, then you will need to set the same hashAlgorithmType in Identity server configuration. 

    In the Sitecore ID server, go to \sitecore\Sitecore.Plugin.IdentityServer\Config\identityServer.xml file and set the same hashAlgorithmType which is used in source server in <PasswordHashAlgorithm> tag. Do not forget to recycle the Identity server application pool after this change. 


Sitecore Upgrade - Transfer Sitecore Membership User/Roles and Password

As part of the Sitecore upgrade, if you have a requirement to transfer Sitecore Membership roles, users and their password, then you can follow this process. 

In case if you have upgraded the core database from one Sitecore version to another, you may not be able to use the same password unless you reset it. 

Transfer Users and Roles using Sitecore Package
To transfer the users and roles, you can use Sitecore Package or by serializing user accounts on one instance and de-serializing them on another instance or easiest way is it to use Sitecore PowerShell Extension. Below piece of script will get all the users and roles from the current version and provide a package.

Once the package is ready, you can use Sitecore Package Installer to install and click Continue Always if there is an user or role already available in the destination server, you can click Continue Always to proceed. 

Transfer Password to new environment
Bringing the users and roles to the new environment will not bring the password. It may be necessary to manually reset user passwords after the transfer. Sitecore provided a simple utility to transfer the passwords to the destination server. Sitecore KB

You have to place the admin web page, provide the source and destination core or security db connection string. You will get an option to select the users to migrate their passwords. In the Sitecore provided file, you have to select one user at a time to move from left to right. 

I modified to add a button to transfer all the available user's passwords in a single click of a button (Transfer All). You can get the updated file here in GitHub

Note: In order for the tool to list the users, you need to make sure the users are already transferred to the destination Sitecore instance. 



11 June, 2021

Sitecore - Post condition failed exception

After upgrading from Sitecore 9.0.1 to Sitecore 10.0.1, there was an error reported in CD environment. "Post condition failed"

This is due to the reference of Core Database in CD server. From Sitecore 9.2, Sitecore has removed the reference of core database in Content Delivery and introduced Security database connection string which can store the aspnet membership tables. 

In my case, I had a reference of Core database in a custom configuration which modified the prefetch cacheSize. Once I removed it, site loaded fine. 
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <databases>
      <database id="core">
        <dataProviders hint="list:AddDataProvider">
          <dataProvider param1="$(id)">
            <prefetch>
              <cacheSize>200MB</cacheSize>
            </prefetch>
          </dataProvider>
        </dataProviders>
      </database>      
  </sitecore>
</configuration>

Exception:
Event code: 3005 
Event message: An unhandled exception has occurred. 
Event time: 6/11/2021 10:32:01 AM 
Event time (UTC): 6/11/2021 3:32:01 PM 
Event ID: 8bb3c123c9f64b1dbf6201fddf35994b 
Event sequence: 2 
Event occurrence: 1 
Event detail code: 0 
 
Application information: 
    Application domain: /LM/W3SVC/2/ROOT-3-132678991184217924 
    Trust level: Full 
    Application Virtual Path: / 
    Application Path: C:\inetpub\wwwroot\cd\ 
    Machine name: CD 
 
Process information: 
    Process ID: 11156 
    Process name: w3wp.exe 
    Account name: IIS APPPOOL\cd 
 
Exception information: 
    Exception type: InvalidOperationException 
    Exception message: Post condition failed
   at Sitecore.Diagnostics.Assert.ResultNotNull[T](T result, String message)
   at Sitecore.Configuration.DefaultFactory.GetDatabase(String name)
   at Sitecore.Configuration.DefaultFactory.GetDatabases()
   at Sitecore.Data.Managers.DefaultItemManager.Initialize()
   at (Object , Object )
   at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
   at (Object , Object )
   at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
   at Sitecore.Pipelines.DefaultCorePipelineManager.Run(String pipelineName, PipelineArgs args, String pipelineDomain, Boolean failIfNotExists)
   at Sitecore.Pipelines.DefaultCorePipelineManager.Run(String pipelineName, PipelineArgs args, String pipelineDomain)
   at Sitecore.Nexus.Web.HttpModule.Application_Start()
   at Sitecore.Nexus.Web.HttpModule.Init(HttpApplication app)
   at System.Web.HttpApplication.RegisterEventSubscriptionsWithIIS(IntPtr appContext, HttpContext context, MethodInfo[] handlers)
   at System.Web.HttpApplication.InitSpecial(HttpApplicationState state, MethodInfo[] handlers, IntPtr appContext, HttpContext context)
   at System.Web.HttpApplicationFactory.GetSpecialApplicationInstance(IntPtr appContext, HttpContext context)
   at System.Web.Hosting.PipelineRuntime.InitializeApplication(IntPtr appContext)

 
 
Request information: 
    Request URL: https://cd:443/
    Request path: /
    User host address: 192.168.1.137 
    User:  
    Is authenticated: False 
    Authentication Type:  
    Thread account name: IIS APPPOOL\cd 
 
Thread information: 
    Thread ID: 31 
    Thread account name: IIS APPPOOL\cd 
    Is impersonating: False 
    Stack trace:    at Sitecore.Diagnostics.Assert.ResultNotNull[T](T result, String message)
   at Sitecore.Configuration.DefaultFactory.GetDatabase(String name)
   at Sitecore.Configuration.DefaultFactory.GetDatabases()
   at Sitecore.Data.Managers.DefaultItemManager.Initialize()
   at (Object , Object )
   at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
   at (Object , Object )
   at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
   at Sitecore.Pipelines.DefaultCorePipelineManager.Run(String pipelineName, PipelineArgs args, String pipelineDomain, Boolean failIfNotExists)
   at Sitecore.Pipelines.DefaultCorePipelineManager.Run(String pipelineName, PipelineArgs args, String pipelineDomain)
   at Sitecore.Nexus.Web.HttpModule.Application_Start()
   at Sitecore.Nexus.Web.HttpModule.Init(HttpApplication app)
   at System.Web.HttpApplication.RegisterEventSubscriptionsWithIIS(IntPtr appContext, HttpContext context, MethodInfo[] handlers)
   at System.Web.HttpApplication.InitSpecial(HttpApplicationState state, MethodInfo[] handlers, IntPtr appContext, HttpContext context)
   at System.Web.HttpApplicationFactory.GetSpecialApplicationInstance(IntPtr appContext, HttpContext context)
   at System.Web.Hosting.PipelineRuntime.InitializeApplication(IntPtr appContext)
 

04 June, 2021

Sitecore RenderingContext.Current.Rendering.Item changed? - Sitecore 9 vs Sitecore 10

As part of  Sitecore 9 to Sitecore 10 upgrade, few components did not work after the upgrade and it was related to the rendering datasource.

Problem: I have a datasource on an ancestor Controller rendering. Child Controller rendering does not have a datasource. Child Controller rendering uses ancestor rendering datasource Item to render the data. After the Sitecore 10 upgrade, Child Controller rendering couldn't get the ancestor datasource item using RenderingContext.Current.Rendering.Item and instead it returned page content Item. 

There is a great blog on Sitecore MVC Rendering datasource topic by Matthew Dresser. He explains about RenderingContext.Current.Rendering.Item clearly. It helps to "get datasource of the current rendering, or the datasource of an ancestor rendering if specified, or the page item if no datasource set and no ancestor rendering with datasource. Rendering datasource takes priority". Datasource of an ancestor rendering will be returned if the setting Mvc.AllowDataSourceNesting is true. It is true by default.

After the upgrade, RenderingContext.Current.Rendering.Item does not return ancestor rendering datasource and instead it returns Page context item. 

Raised a Sitecore Support ticket whether it is an expected change or a bug. Will update once I hear from them.

As workaround, I wanted it to behave in the same fashion to reduce the impact. I added a wrapper method which gives priority to child rendering datasource if available, then ancestor rendering datasource if available and then page context item. 

References:

01 June, 2021

ReferenceError: URL is not defined

If you are using Node 8.11.2-x64, you may experience the below error when trying to fetch client packages like bootstrap or jquery from the source. 

1579 verbose stack ReferenceError: URL is not defined
1579 verbose stack     at regKeyFromURI (C:\Users\Nehem\AppData\Roaming\npm\node_modules\npm\node_modules\npm-registry-fetch\auth.js:7:18)
1579 verbose stack     at getAuth (C:\Users\Nehem\AppData\Roaming\npm\node_modules\npm\node_modules\npm-registry-fetch\auth.js:49:18)
1579 verbose stack     at regFetch (C:\Users\Nehem\AppData\Roaming\npm\node_modules\npm\node_modules\npm-registry-fetch\index.js:55:16)
1579 verbose stack     at RemoteFetcher.[pacote.Fetcher._tarballFromResolved] (C:\Users\Nehem\AppData\Roaming\npm\node_modules\npm\node_modules\pacote\lib\remote.js:40:5)
1579 verbose stack     at tryAgain (C:\Users\Nehem\AppData\Roaming\npm\node_modules\npm\node_modules\pacote\lib\fetcher.js:303:64)
1579 verbose stack     at C:\Users\Nehem\AppData\Roaming\npm\node_modules\npm\node_modules\promise-retry\index.js:29:24
1579 verbose stack     at <anonymous>

Permanent Fix: Upgrade the node to v9.8.0 which will resolve the issue. 

Workaround: In case if you can't or don't want to upgrade, you can add the var URL = require('url').URL; in the js file mentioned in the stacktrace (here: \node_modules\npm-registry-fetch\auth.js) and it should resolve the issue. Stackoverflow reference

28 May, 2021

Sitecore Upgrade - Codebase Upgrade Series - Remove unused references and nuget packages

As part of the Sitecore codebase upgrade series, in this blog, we are going to deal with unused references and packages. It is worth to cleanup the unused references and nuget packages to reduce the complexity, dependencies and effort to upgrade to be compatible with target Sitecore version. 

Remove Unused References:

Visual Studio 2019 has the inbuilt "Remove Unused References" option for .NET framework projects with .NET SDK project format and .NET core projects. If the project type is already in .NET SDK format, then right click on project or on the references and select Remove Unused References. Then select the list of references to remove and click Apply. As of Visual Studio 2019 v16.10.0, this option is turned off by default. To enable it, you can go to menu Tools > Options > Text Editor > C# > Advanced. Select the Remove Unused References command in Solution Explorer. 




Remove Unused Packages

To remove Unused packages, you may want to get ReSharper which can clean up the unused references and also remove the unused packages. If ReSharper is installed, you can refactor the entire solution or a particular project. Right Click on the Solution > Refactor > Remove Unused References. This opens up a window with the list of references and packages and you can select and remove it. This will remove the entry from Packages.config or from PackageReferences if it is used. 

There are other open source extensions in Visual Studio Gallery and few proprietary tools like CoreRush or Telerik® JustCode™ are available in the market which must be doing the same tasks. 



07 May, 2021

Visual Studio - PowerShell Package Manager Console Reload Profile Script

In case if you are setting up a NuGet PowerShell profile or modifying the profile script for Visual Studio PowerShell Package Manager Console, you will need to close and open the Visual Studio to reload the profile methods. 

To reload the profile scripts without closing and opening the Visual Studio, you can run the below command. This will reload the profile script and the updated method will be available for you to use in Console. 

. $profile

06 May, 2021

Sitecore Upgrade - Sitecore NuGet Package Upgrade using PowerShell

This blog is related to thSitecore codebase upgrade series.

Sitecore enabled package management system for the Sitecore packages from version 9.x. This has helped to avoid unnecessary and complicated reference management. In order to do .NET framework upgrade and Sitecore NuGet package upgrade, there are various ways as follows.
  1. Using NuGet Package Manager 
  2. Using PowerShell Package Manager Console
  3. NuGet CLI
  4. dotnet CLI
Certain Sitecore Helix solution may have 100s of projects so using NuGet Package Manager in Visual Studio may not be productive. As a programmer, you can leverage the PowerShell Package Manager Console to inspect each project and update the packages. 

Gary has written a script to update the Sitecore Packages and as he mentioned, it is easy to extend and tweak it as per our need. One of my requirement is to find the projects which are having Sitecore Packages and update all the packages to the target version in a single shot.  

The below script accepts the old package version and the new package version and finds all the projects having "Sitecore." packages and upgrades the packages to the target version along with dependencies. Save the gist file as nuget_Profile.ps1 in C:\Users\[user]\Documents\WindowsPowerShell folder and restart the Visual Studio for the PowerShell Package Manager console to pick up the profile scripts. 
  1. Finds all the projects with Sitecore packages
  2. Loop through each projects and updates the Sitecore Packages.
  3. If NoReference Package is installed, it finds the alternative package with NoReference and installs it. 
In the PowerShell Package Manager console, execute the method along with old and new package version as below. Please note script is defaulted to version 9.3.0 as old version and version 10.1.0 as the new version. 
UpdateSitecorePackagesForAllProjects -NewVersion 9.0.171219 -OldVersion 10.0.1



01 May, 2021

Sitecore Upgrade - Codebase Upgrade Series

One of the task in a Sitecore upgrade project is to upgrade the codebase to be compatible with the target Sitecore version. I have listed some of the steps which I learnt and it helped me to upgrade the solution quickly. 

  1. Remove unused references and nuget packages
  2. Framework upgrade - .NET
  3. Migrate to SDK Project Format (optional)
  4. Migrate from packages.config to PackageReference
  5. Replace Sitecore assemblies reference with nuget package
  6. Upgrade Sitecore nuget packages
  7. Upgrade .NET related nuget packages
  8. Upgrade 3rd party nuget packages
  9. Compile, replace obsolete methods and fix errors
Before upgrading the codebase, make sure to create a separate branch so that it does not affect the ongoing development tasks. 

Visual Studio PowerShell related articles to run scripts. 


Sitecore Upgrade related articles.





30 April, 2021

Sitecore Marketing Automation Engine failed to start - Workaround for local development

There are several blogposts related to Sitecore Marketing Automation Engine service which is not getting started and Sitecore installation abruptly stops. If it is failing in a production instance, then please do refer the blogpost links at the bottom of this blog to find the root cause and fix it. 

In case, it is for a local development instance and you just want to complete the installation and bring up the Sitecore, you can do the following workaround to install the Sitecore successfully and also bring up the Sitecore Marketing Automation Engine service. 

Installation using SIF:

Edit the xconnect-xp0.json file, go to StartServices task and remove the params to start the marketing automation service. This will allow you to complete the Sitecore installation. Basically we are removing the task to start the service as part of the installation. 

        "StartServices": {
            "Description": "Starts the service.",
            "Type": "ManageService",
            "Params": [
                {
                    "Name": "[variable('Services.IndexWorker.Name')]",
                    "Status": "Running"
                },
                {
                    "Name": "[variable('Services.ProcessingEngine.Name')]",
                    "Status": "Running"
                }
            ]
        }

Installation using sifon or SIM:

Open the compressed installation package using 7-Zip (SIF - \AppData\Roaming\Sitecore\Sitecore Instance Manager\Repository or sifon - c:\Program Files\Sifon\Downloads\), edit the xconnect-xp0.json file directly inside the package, go to StartServices task and remove the params to start the marketing automation service. This will allow you to complete the Sitecore installation.

Start Sitecore Marketing Automation Engine:

Most of the time, this issue happens due to certification. So we can let the xConnection to ignore the certificate validation. Since it is a local development environment, edit xConnect application AppSettings.config, and remove entry with key - validateCertificateThumbprint, save it. Recycle the xConnect application pool and try to start the Sitecore Marketing Automation Engine service and it should work. 

  <!-- Remove this entry and save it. -->
  <add key="validateCertificateThumbprint" value="A24A5C1386846F69A69BD8C0BCC78FA1454872E1" />  

Related blogposts to find the root cause and fix it:

http://www.nehemiahj.com/2021/06/sitecore-marketing-automation-engine.html

installation failure, fails to start marketing automation service - Installation and Upgrading Sitecore - Developers - Sitecore Community

Sitecore 9.1 Failed to start Marketing Automation Service – Sitecore Endeavor (wordpress.com)

xConnect The HTTP response was not successful: Unauthorized - Sitecore Stack Exchange

29 April, 2021

Adding Solr Certificate Store Password with Special Characters in Windows batch file

As part of Sitecore IaaS setup, I had a chance to do On-Premise Solr setup. To enable SSL for Solr, we need a certificate which can be self-signed or CA signed and the store password. In order to enable the SSL for Solr, we need to install the certificate and then we need to edit batch file "\bin\solr.in.cmd" and paste the store password along with the certificate (crt, pfx) file. 

In this example, secret is the password. 

set SOLR_JAVA_HOME="C:\Solr\solr-8.4.0\jdk8u222-b10-jre"
set SOLR_SSL_KEY_STORE=etc/solr-ssl.keystore.jks
set SOLR_SSL_KEY_STORE_PASSWORD=secret
set SOLR_SSL_TRUST_STORE=etc/solr-ssl.keystore.jks
set SOLR_SSL_TRUST_STORE_PASSWORD=secret
set SOLR_HOST="localhost"
set SOLR_Port=8840

Sometimes the provided password for the certificate from the vendor may have some special characters. Since the password with special character has to be entered in the batch file, batch execution will fail and Solr will fail to start with errors like "Keystore was tampered with, or password was incorrect" or "Password verification failed". 

As per Microsoft documentation, there are few limitations when we use SET command in batch file with value string containing special characters like <, >, |, &, and ^. You can escape the special character or you can load the string value from a file without escaping. 

To load the value string with special characters from a file:

  1. Create a file named "key", add the password string with special character and save it in /bin folder. 
  2. Modify the solr.in.cmd file to pick the value string from this file as below.
set /p SOLR_SSL_TRUST_STORE_PASSWORD=<key
set /p SOLR_SSL_KEY_STORE_PASSWORD=<key
Error log from Solr:
2021-04-30 14:30:48.106 ERROR (main) [   ] o.a.s.s.SolrDispatchFilter Could not start Solr. Check solr/home property and the logs
2021-04-30 14:30:48.128 ERROR (main) [   ] o.a.s.c.SolrCore null:org.apache.solr.common.SolrException: Error instantiating shardHandlerFactory class [HttpShardHandlerFactory]: java.io.IOException: Keystore was tampered with, or password was incorrect
	at org.apache.solr.handler.component.ShardHandlerFactory.newInstance(ShardHandlerFactory.java:56)
	at org.apache.solr.core.CoreContainer.load(CoreContainer.java:633)
	at org.apache.solr.servlet.SolrDispatchFilter.createCoreContainer(SolrDispatchFilter.java:262)
	at org.apache.solr.servlet.SolrDispatchFilter.init(SolrDispatchFilter.java:182)
	at org.eclipse.jetty.servlet.FilterHolder.initialize(FilterHolder.java:136)
	at org.eclipse.jetty.servlet.ServletHandler.lambda$initialize$0(ServletHandler.java:750)
	at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
	at java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:742)
	at java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:742)
	at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:647)
	at org.eclipse.jetty.servlet.ServletHandler.initialize(ServletHandler.java:744)
	at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:369)
	at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1497)
	at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1459)
	at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:854)
	at org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContextHandler.java:278)
	at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:545)
	at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
	at org.eclipse.jetty.deploy.bindings.StandardStarter.processBinding(StandardStarter.java:46)
	at org.eclipse.jetty.deploy.AppLifeCycle.runBindings(AppLifeCycle.java:192)
	at org.eclipse.jetty.deploy.DeploymentManager.requestAppGoal(DeploymentManager.java:510)
	at org.eclipse.jetty.deploy.DeploymentManager.addApp(DeploymentManager.java:153)
	at org.eclipse.jetty.deploy.providers.ScanningAppProvider.fileAdded(ScanningAppProvider.java:172)
	at org.eclipse.jetty.deploy.providers.WebAppProvider.fileAdded(WebAppProvider.java:436)
	at org.eclipse.jetty.deploy.providers.ScanningAppProvider$1.fileAdded(ScanningAppProvider.java:65)
	at org.eclipse.jetty.util.Scanner.reportAddition(Scanner.java:610)
	at org.eclipse.jetty.util.Scanner.reportDifferences(Scanner.java:529)
	at org.eclipse.jetty.util.Scanner.scan(Scanner.java:392)
	at org.eclipse.jetty.util.Scanner.doStart(Scanner.java:313)
	at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
	at org.eclipse.jetty.deploy.providers.ScanningAppProvider.doStart(ScanningAppProvider.java:145)
	at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
	at org.eclipse.jetty.deploy.DeploymentManager.startAppProvider(DeploymentManager.java:598)
	at org.eclipse.jetty.deploy.DeploymentManager.doStart(DeploymentManager.java:240)
	at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
	at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:167)
	at org.eclipse.jetty.server.Server.start(Server.java:418)
	at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:119)
	at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:113)
	at org.eclipse.jetty.server.Server.doStart(Server.java:382)
	at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
	at org.eclipse.jetty.xml.XmlConfiguration.lambda$main$0(XmlConfiguration.java:1797)
	at java.security.AccessController.doPrivileged(Native Method)
	at org.eclipse.jetty.xml.XmlConfiguration.main(XmlConfiguration.java:1746)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.eclipse.jetty.start.Main.invokeMain(Main.java:220)
	at org.eclipse.jetty.start.Main.start(Main.java:490)
	at org.eclipse.jetty.start.Main.main(Main.java:77)
Caused by: java.lang.RuntimeException: java.io.IOException: Keystore was tampered with, or password was incorrect
	at org.apache.solr.client.solrj.impl.Http2SolrClient.createHttpClient(Http2SolrClient.java:224)
	at org.apache.solr.client.solrj.impl.Http2SolrClient.&lt;init&gt;(Http2SolrClient.java:154)
	at org.apache.solr.client.solrj.impl.Http2SolrClient$Builder.build(Http2SolrClient.java:833)
	at org.apache.solr.handler.component.HttpShardHandlerFactory.init(HttpShardHandlerFactory.java:321)
	at org.apache.solr.handler.component.ShardHandlerFactory.newInstance(ShardHandlerFactory.java:51)
	... 50 more
Caused by: java.io.IOException: Keystore was tampered with, or password was incorrect
	at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:785)
	at sun.security.provider.JavaKeyStore$JKS.engineLoad(JavaKeyStore.java:56)
	at sun.security.provider.KeyStoreDelegator.engineLoad(KeyStoreDelegator.java:224)
	at sun.security.provider.JavaKeyStore$DualFormatJKS.engineLoad(JavaKeyStore.java:70)
	at java.security.KeyStore.load(KeyStore.java:1445)
	at org.eclipse.jetty.util.security.CertificateUtils.getKeyStore(CertificateUtils.java:54)
	at org.eclipse.jetty.util.ssl.SslContextFactory.loadKeyStore(SslContextFactory.java:1194)
	at org.eclipse.jetty.util.ssl.SslContextFactory.load(SslContextFactory.java:334)
	at org.eclipse.jetty.util.ssl.SslContextFactory.doStart(SslContextFactory.java:256)
	at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
	at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:167)
	at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:119)
	at org.eclipse.jetty.client.HttpClient.doStart(HttpClient.java:244)
	at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68)
	at org.apache.solr.client.solrj.impl.Http2SolrClient.createHttpClient(Http2SolrClient.java:222)
	... 54 more
Caused by: java.security.UnrecoverableKeyException: Password verification failed
	at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:783)

13 April, 2021

Sitecore Publishing Service - Recap

This blog is a recap of the Sitecore Publishing Service.

Sitecore introduced Sitecore Publishing Service along with Sitecore v8.2. It is a standalone service which reads the dedicated Publish Queue, create Manifest of items to be changed and process the content movement from source to target.

This standalone service is optional and independent of out of the box Sitecore publishing mechanism in CM. This service helps clients where there is a frequent content changes and multiple content authors. This reduces the load on the CM instance as the entire publishing mechanism will be lifted and handled by Publishing Service. This service also raises the events to clear the cache after the publish. In case if we want to raise custom event, we can patch it and let this service raise the event.

To install this service, there are two steps.

  1. Sitecore Publishing Service which needs .NET core and can be hosted in IIS or any other platform. 
  2. Sitecore Module which needs to be installed in the Content Management server. 
    • This module enabled a Publishing Dashboard which will read the publish job queue and provide a status to the content authors. 
    • It also creates a role by which we can control the full publish to certain users. 
    • It creates a set of tables in the master DB so the connection string user for master DB should have access to create table while this package is installed. 

blockquote { margin: 0; } blockquote p { padding: 15px; background: #eee; border-radius: 5px; } blockquote p::before { content: '\201C'; } blockquote p::after { content: '\201D'; }