Tuesday, May 31, 2022

Different Ways of Handling Redirects in Sitecore Headless JSS NextJS App

 There are several ways to handle custom redirects in NextJS app for Sitecore Headless.


1. Using redirects configurations defined on next.config.js file

We can use NextJS provided redirect functionality for this. We can either define these directly on the next.config.js file's "redirects" section OR can move that to a separate file and include it like below.



NOTE: Needs to include redirects.js file onto next.config.js to get the ...redirectsConfig
const redirectsConfig = require('./src/next-config/redirects');


2. Using Sitecore Redirect Template item

We wanted a way to provide a method to add redirects in case editors wanted to add that url into dynamically generated menus on the site.

So we decided to take the custom Redirect App Route template with RedirectURL field in it.


When this page is requested, we check the RedirectURL field value and do the redirect from getServerSideProps method on [[...path]].tsx page.

This called handling redirects from server side in NextJS app.

Code will look like something below:






3. Using redirects defined in a separate tree section in the Sitecore content tree

This will allow to add multiple redirects without actually having to have a Redirect Sitecore Item defined/created.

This will be same as existing SXA OR Url Rewrite module item structure with separate redirects defined.

But we will use GraphQL to retrieve those data using Sitecore Layout Service and then do the necessary redirects from NextJS server side.

Expect a separate blog post on this in future.


4. Using Vercel app redirects


Vercel also supports defining redirects in Vercel itself. 

Wednesday, May 19, 2021

Saying Goodbye to Sitecore Community

After working 12 years with Sitecore community, I'm moving away from my community contributions.

Some of you might know me well as Sitecore Footsteps (Twitter: scFootsteps).

For those who don't know me earlier, I'm a 6 times Sitecore Technology MVP (2016 - 2021) from in Sri Lanka. I'm working with Sitecore product from year 2010. Currently I'm working as a Freelance Sitecore Consultant.


In the past 12 years, I have contributed to the community by:

- Blogs

- Presentations at Events

- Organising user group events

- YouTube videos

- Sitecore Slack/StackExchange/Sitecore Community site 

- Providing feedback to Sitecore related to their product/releases & trainings 


I was initially awarded Sitecore MVP title in 2016 (https://sitecorefootsteps.blogspot.com/2016/02/sitecorefootsteps-chaturanga-ranatunga.html) and was awarded the title continuously for 6 years now.


Main reasons for this decision is, I'm starting to lose interest on Sitecore development. Losing the interest in Sitecore development is mainly due to my personal interest and nothing mentioned here relates to Sitecore product.


I'm thanking all the teams that I have worked with (as a full-time employee & as a contractor), all the community contributors including MVPs and Sitecore technical marketing team.

It was great fun meeting all my Sitecore friends that I initially only knew through forums & twitter. 


What's for me in future,

Currently I don't have a clear idea on which path I will take after this. 

I will continue to work as Freelance/Contract Sitecore Consultant, which still help pay my bills :-)

Also I have started to learn new technologies and will try to implement/code few test solutions using those technologies.


Wish you all best for all the Sitecore community... :-)



Blog           https://sitecorefootsteps.blogspot.com

YouTube    Sitecore for Dummies

Twitter       https://twitter.com/scfootsteps

LinkedIn    https://lk.linkedin.com/in/chaturanga

          Old Forum Username: chaturangar







Saturday, February 20, 2021

Announcement: For the 6th Consecutive Year, scFootsteps' Chaturanga Ranatunga, was Awarded Sitecore Most Valuable Professional Award 2021

Recently Sitecore announced list of Sitecore Most Valuable Professional (MVP) award winner for year 2021.

For the 6th continuous year, I was also awarded the Sitecore Technology MVP award. (http://mvp.sitecore.com)


If I talk little bit history with my Sitecore development involvement:

When I started Sitecore development work, it was year 2010 with Sitecore 6.4. 

11 years went past, with Sitecore is now in Sitecore 10.0 version.

And in year 2016, I was first awarded my first MVP title.

I'm the first and only Sitecore MVP in my country, Sri Lanka.


Last year (Year 2020) was a tough year for everyone due to pandemic. Due to that same reason, most of the on-site meet-ups & conferences was cancelled.

But I was lucky enough to be selected and to be able to presented at the Global Virtual SUGCON 2020.


Hopefully we will be able to meet again in person with all the Sitecore Community.

Until then, happy Sitecore!!


Friday, November 27, 2020

Edit and Update Sitecore Cloud WebDeployment Package using Sitecore Azure Toolkit

Sometimes you will need to adjust the default web deploy packages provided to add new functionality or adjust existing functionality. 


You cannot edit these WebDeploy packages by just extracting.


You have to use "Sitecore Azure Toolkit" PowerShell module to update these packages.


Below I have inserted a script that I used to update existing WebDeploy package with adjusted settings and files.


Most of the content in the internet describing this process is not complete and hard for a beginner to understand.

Following was the only blog post that explained the process that I got the basic idea on what needs to be done.

http://www.chrissulham.com/modify-sitecore-install-framework-packages-for-azure-sql/


Unfortunately that blog page seems not available at the moment. Archive of that blog post can be found from below url.


https://web.archive.org/web/20191102122827/http://www.chrissulham.com/modify-sitecore-install-framework-packages-for-azure-sql/


Preparing Files to Update WebDeploy Package

Following is the structure of my "Sitecore 10.0.0 rev. 004346 (Cloud)_cd.scwdp" folder where I have following files to replace in original WebDeploy package. You can add the changed or new files into "C:\Work\ARMTemplates\Sitecore 10.0 XP Packages\XP\Generated\Sitecore 10.0.0 rev. 004346 (Cloud)_cd.scwdp" folder.


Since I'm only adding a new connection string to ConnectionStrings.config file by capturing the parameters values returned from azure deployment, I only have following two files.


/CopyToRoot/parameters.xml

/CopyToWebsite/App_Config/ConnectionStrings.config





More info on how to organise folder structure inside the new package files can be read from https://doc.sitecore.com/developers/sat/20/sitecore-azure-toolkit/en/the-structure-of-an-sccpl-transformation.html


Import and Running Script

Step 1: Download Sitecore Azure Toolkit

Download and unzip latest "Sitecore Azure Toolkit" from Sitecore to "C:\Work\ARMTemplates\Sitecore Azure Toolkit 2.5.0-r02519.1061" folder.


Step 2: Run following script 

In this script I'm trying to update the default Sitecore 10 XP Cloud WebDeploy package with the changes I did to include some extra connection string to ConnectionString.config file.

Clear-Host


##Import Az Module

Import-Module -Name Az


# This is the location of the local repoitory and will need to be updated to refect the location of where this script # is being run from.

$basePath = "C:\Work\ARMTemplates"


## Configuration

$SCSdkPSM1 = "$basePath\Sitecore Azure Toolkit 2.5.0-r02519.1061\tools\Sitecore.Cloud.Cmdlets.psm1"

$SCSdkDLL = "$basePath\Sitecore Azure Toolkit 2.5.0-r02519.1061\tools\Sitecore.Cloud.Cmdlets.dll"



## Initialize/import the modules

Import-Module $SCSdkPSM1 -Verbose

Import-Module $SCSdkDLL -Verbose



## Payload package generation

New-SCCargoPayload -Path 'C:\Work\ARMTemplates\Sitecore 10.0 XP Packages\XP\Generated\Sitecore 10.0.0 rev. 004346 (Cloud)_cd.scwdp' -Destination 'C:\Work\ARMTemplates\Sitecore 10.0 XP Packages\XP\Generated' -Verbose -Force



## Update WDP package generation

Update-SCWebDeployPackage -CargoPayloadPath 'C:\Work\ARMTemplates\Sitecore 10.0 XP Packages\XP\Generated\Sitecore 10.0.0 rev. 004346 (Cloud)_cd.scwdp.sccpl' -Path 'C:\Work\ARMTemplates\Sitecore 10.0 XP Packages\GeneratingNewWDPPackages\Generated\Sitecore 10.0.0 rev. 004346 (Cloud)_cd.scwdp.zip'



New-SCCargoPayload command will create .sccpl payload package

Update-SCWebDeployPackage command will update the scwdp.zip WebDeploy package



Following is the final results after running the above script

Sitecore 10.0.0 rev. 004346 (Cloud)_cd.scwdp folder             - New/Edited files

Sitecore 10.0.0 rev. 004346 (Cloud)_cd.scwdp.sccpl folder   - Payload package created from New-SCCargoPayload command

Sitecore 10.0.0 rev. 004346 (Cloud)_cd.scwdp.zip folder       - Final WebDeploy package created from Update-SCWebDeployPackage command




Extra Information:

https://www.credera.com/blog/technology-solutions/how-to-deploy-sitecore-to-azure-part-1-environment-setup/
https://doc.sitecore.com/developers/sat/20/sitecore-azure-toolkit/en/web-deploy-packages-for-a-module.html
https://blog.baslijten.com/sitecore-on-azure-create-custom-web-deploy-packages-using-the-sitecore-azure-toolkit/


Thursday, October 8, 2020

Sitecore 10 Azure Deployment ARM Templates Hidden Option to Have Separat CM and Reporting WebApp Hosting Plans

Recently I was working on preparing ARM templates for Sitecore 10 Azure PaaS environment deployment.

One of the requirements client had was to have a separate Hosting Plans for CM web app and Reporting web app, which will allow the client to scale up/down the performance of CM & Reporting web apps separately.

So I took the Sitecore 10 ARM templates from GitHub repository (https://github.com/Sitecore/Sitecore-Azure-Quickstart-Templates)  and tried to deploy a "Small" size azure environment with Sitecore XP Scale ARM templates. 

Once the deployment went successful, I tried to verify the deployed environments with the requested environment topology. Everything was deployed correctly except for the CM & Reporting Web Apps shared a common single Hosting plan (i.e. CM Hosting Plan).

So I thought I will have to adjust the default Sitecore 10 ARM templates by adding new Hosting Plan configuration and then changed the Reporting Web App to use this newly added hosting plan. 

While I was trying to investigate on how to add this new hosting plan, I saw following configuration on Reporting Web app.



As you can see, there was actually an optional configuration by default in Sitecore 10 ARM templates, where we can tell the deployment to either use CM hosting plan OR a separate hosting plan for Reporting web app.

\Sitecore 10.0 XP ARM Template\nested\infrastructure.json 

....

"serverFarmId": "[if(parameters('useDedicatedHostingPlanForReporting')

          resourceId('Microsoft.Web/serverfarms', variables('repHostingPlanNameTidy')), 

          resourceId('Microsoft.Web/serverfarms', variables('cmHostingPlanNameTidy')))]",

.... 

 Also there was this "useDedicatedHostingPlanForReporting" parameter defined on "azuredeploy.json" file as boolean type.

"useDedicatedHostingPlanForReporting": {

"type": "bool",

"defaultValue": false

},

So what just had to do was, to provide value to that variable from my azuredeploy.parameters.json file.

"useDedicatedHostingPlanForReporting" : {

  "value": true

},

That was it. Just ran the deployment and now I have CM & Reporting web apps running on their own two separate hosting plans.


Happy Sitecore !!!

Thursday, February 13, 2020

For the 5th Consecutive Year, scFootsteps' Chaturanga Ranatunga Wins Sitecore Most Valuable Professional Award 2020

scFootsteps' Chaturanga Ranatunga Wins Sitecore Most Valuable Professional Award
Elite distinction awarded for commitment and dedication to the Sitecore community





Colombo, Sri Lanka — February, 04, 2020 — scFootsteps' Chaturanga Ranatunga, today announced that Chaturanga, Independent Sitecore Consultant has been named a Most Valuable Professional (MVP) in the Technology category for the 5th consecutive year by Sitecore®, the global leader in digital experience management software. Chaturanga Ranatunga was one of only 154 Technology MVPs worldwide to be named a Sitecore MVP this yearnot to mention the only person from Sri Lanka to be named a Sitecore MVP 2020.

Recognizing professionals within the Sitecore community who actively apply their talent and expertise to help others best utilize Sitecore products to deliver premier customer experiences, the MVP program is now in its 14th year. Of more than 13,000 certified developers and over 24,000 active community participants, the 316 MVPs are truly an elite group. This year’s MVPs were selected for the quality, quantity and impact of the contributions they made in 2019, including the sharing of product expertise and mastery of the Sitecore platform to support both partners and customers. 

As a Sitecore Freelance Consultant with more than 10 years of Sitecore development experience and overall 12 years in the software industry, I've thoroughly enjoyed sharing my expertise of Sitecore products, including on this blog and through the other community channels. (scFootsteps - Chaturanga Ranatunga)

 “One of our greatest assets is the highly collaborative Sitecore community, where members share technical knowledge and insights across numerous channels and at events to help each other build greater digital experiences for their organizations and customers,” said Pieter Brinkman, Senior Director of Technical Marketing at Sitecore. “Sitecore MVPs stand out as leaders within the community for their passion and willingness to invest their own time with contributions ranging from educational blogs, videos, podcasts and speaking engagements to community engagement and support on social media and forums. They are an invaluable resource and important part of the Sitecore user experience, for which we are truly grateful.”

“Sitecore MVPs are always at the top of the list to get access to the latest developments and offerings from Sitecore, and we will rely on them heavily when we introduce the new Software as a Service offering later this year. I am looking forward to working on this together with this incredible group.” added Brinkman.

Sitecore’s SaaS offering will make it much easier and faster to build digital experiences, while maintaining the flexibility for Sitecore partners and customers to create differentiated experiences. Once a user is on Sitecore’s SaaS platform, they will always have the most current version of the product with the ease of automatic upgrades.

More information can be found about the MVP Program on the Sitecore MVP site: http://mvp.sitecore.com.

Thursday, December 5, 2019

Sitecore Publishing Service 4.1.0 Setup Error With DotNet Core Library

Recently I was trying to set Sitecore Publishing Service 4.1.0 with Sitecore 9.1

While trying to setup the Publishing Service manually, and did the all the steps described in the documentation.
After those I was trying to start the IIS site and then tried to visit the site using following url to verify the solution.

http://sc910.publishing/api/publishing/operations/status

An error occurred while starting the application. .NET Framework 4.8 ...

So then I tried to start the publishing service as a service from Powershell using following command and it also returned following error message.

.\Sitecore.Framework.Publishing.Host --urls 'http://sc910.publishing:5000' -environment Development

Application startup exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.IO.FileLoadException: Could not load file or assembly 'Serilog.AspNetCore, Version=2.0.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10' or one of its dependencies. Operation is not supported. (Exception from HRESULT: 0x80131515) ---> System.NotSupportedException: An attempt was made to load an assembly from a network location which would have caused the assembly to be sandboxed in previous versions of the .NET Framework. This release of the .NET Framework does not enable CAS policy by default, so this load may be dangerous. If this load is not intended to sandbox the assembly, please enable the loadFromRemoteSources switch. See http://go.microsoft.com/fwlink/?LinkId=155569 for more information.
   --- End of inner exception stack trace ---
   at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)


Error was complaining about "Serilog.AspNetCore.dll" which comes with the Publishing service installation.

What I did was, I open the properties of that dll and click "Unlock" button in the popup window.

Then, Sitecore Publishing Service start to work as expected.



Happy Sitecore!

Friday, November 8, 2019

Sitecore 9 GEO IP Service Fails When xConnect is Down

Just wanted to share small but valuable point I learned recently.

We faced a same issue on two of my client's site implementations where their home pages takes 10-15 seconds load. But the other pages inside the site loads without any delays.

We were in contact with Sitecore for this issue and then we got an answer from Sitecore consultancy team.

The issue was related to GEO IP lookup service & xConnect.

On both the solutions I worked, there is a GEO IP lookup call happening on the home page to redirect visitors to their relevant regions.

But due to different reasons (rebooting the xConnect server for maintenance, etc), both of those sites xConnect site was down.

So, when the xConnect is down, GEO IP lookup requests fails to work as required and tries several times to fetch the correct information for the IP. After several attempts it gets failed.
Due to this delay of trying to fetch the IP several times due to failures, home page gets delay to load.

I don't know exact reason why GEO IP lookup needs xConnect site running, but will update here if I find it in future.

Thank you for Sitecore for helping us to find this issue.

Happy Sitecore!!

Thursday, November 7, 2019

Path Analyzer Map Errors Populating Sitecore Logs After Sitecore 9.1 Upgrade

Recently we upgraded a Sitecore 8.1 solution to Sitecore 9.1 Update-1

After the upgrade we rebuild the reporting database. After the reporting database rebuild we started to notice that our Sitecore logs (setup to log level "ERROR") is getting populated with lot of Path Analyzer errors.

7404 18:45:08 ERROR [Path Analyzer] Cannot apply rule on the interaction.
Exception: Sitecore.XConnect.Segmentation.ExpressionBuilder.PredicateDescriptorException
Message: No known predicate type could be determined from ' Sitecore.Analytics.Rules.Conditions.ContactVisitIndexCondition,Sitecore.Analytics' specified in the definition item (Id = '61370693-189d-44a0-abc5-2592dbd579ed', db = 'master') : Could not load type 'Sitecore.Analytics.Rules.Conditions.ContactVisitIndexCondition' from assembly 'Sitecore.Analytics'.
Source: Sitecore.Marketing.Segmentation.xMgmt
   at Sitecore.Marketing.Segmentation.ExpressionBuilder.ContentTreePredicateDescriptorLocator.GetDescriptor(Guid id)
   at Sitecore.Marketing.Segmentation.RuleXmlConverter.ConditionXmlNodeConverter.LookupType(Guid descriptorId)
   at Sitecore.Marketing.Segmentation.RuleXmlConverter.ConditionXmlNodeConverter.ConvertNodeInternal(INodeConversionContext`2 context, XElement element)
   at Sitecore.Marketing.Segmentation.RuleXmlConverter.BaseXmlRuleNodeConverter`1.Convert(INodeConversionContext`2 context, XElement node)
   at Sitecore.Marketing.Segmentation.RuleXmlConverter.AndXmlNodeConverter.ConvertNodeInternal(INodeConversionContext`2 context, XElement element)
   at Sitecore.Marketing.Segmentation.RuleXmlConverter.BaseXmlRuleNodeConverter`1.Convert(INodeConversionContext`2 context, XElement node)
   at Sitecore.XConnect.Segmentation.ExpressionBuilder.TreeConverter.TreeConverter`2.Convert(TFromNode treeRoot)
   at Sitecore.Marketing.Segmentation.RuleXmlConverter.RuleXmlConverter.CreateRule(XElement ruleElement)
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at Sitecore.PathAnalyzer.Rules.RulesBuilder.BuildXmlRules(String rulesXml)
   at Sitecore.PathAnalyzer.Rules.RulesBuilder.BuildRules(String rulesXml)
   at Sitecore.PathAnalyzer.Rules.RulesValidator.ValidateRule(Interaction interaction, String rulesXml, ConditionParameters parameters)
   at Sitecore.PathAnalyzer.Construction.TreeBuilder.IsApplicable(Interaction interaction, String rulesXml, ConditionParameters conditionParameters)
Nested Exception
Exception: System.TypeLoadException
Message: Could not load type 'Sitecore.Analytics.Rules.Conditions.ContactVisitIndexCondition' from assembly 'Sitecore.Analytics'.
Source: mscorlib
   at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMarkHandle stackMark, IntPtr pPrivHostBinder, Boolean loadTypeFromPartialName, ObjectHandleOnStack type)
   at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean loadTypeFromPartialName)
   at System.Type.GetType(String typeName, Boolean throwOnError)
   at Sitecore.Marketing.Segmentation.ExpressionBuilder.ContentTreePredicateDescriptorLocator.GetDescriptor(Guid id)

Unsure if following steps did help, but anyways mentioning them also :

  • Since the item ID mentioned in the error was "/sitecore/system/Settings/Rules/Definitions/Elements/Visitor/Global Visit No", I did try to remove/clean all the items that used this rule 
  • Deleted all the custom Maps from Sitecore 8.1
  • Cleared all the table in the RefData database and Deploy all the Marketing Definitions again
  • Removing EMPTY Site definition entry in "SiteNames" table in Reporting database entry that I removed was SiteNameId was set to 0 & SiteName was empty


But all the above steps did not stopped the error population on the logs.


Then I did the following steps and after the last step the error went away.

Step 1: Delete all the Map definitions from "TreeDefinitions" table in Reporting database

Step 2: Redeploy all Path Analyzer Map definitions by visiting following tool and clicking "Deploy all maps that are not deployed" button
http:/<sitecore_hostname>/Sitecore/admin/pathanalyzer.aspx

Step 3: In the same tool above, click "Rebuild" button on "Historic Map Rebuild" section

NOTE: These were mainly taking from https://sitecore.stackexchange.com/questions/17162/sitecore-9-processing-server-exception-when-executing-agent-pathanalyzer-mapre post on Sitecore StackExchange


Some useful links related to Sitecore Path Analyzer Errors on Log files :

https://sitecore.namics.com/2019/08/14/sitecore-pathanalyzer-undeploy-maps/
https://sitecore.stackexchange.com/questions/11253/no-known-predicate-type-could-be-determined-from-sitecore-analytics-omnichannel
https://blog.wesleylomax.co.uk/posts/2019-08-08-sitecore-9-1-processing-server-an-error-occured-evaluating-the-primary-condition-of-the-rule/




Sunday, October 13, 2019

Sitecore 9 Initial Page Load Deadlock Senario

Recently we have upgraded a solution to Sitecore 9.1.1 and started facing an strange issue.

When we set the Sitecore instance to "ContentDelivery" role from web.config app settings property, front-end site's initial page load request takes ages to respond. After the initial respond site starts to work property.

I tried to look into the issue few days and still couldn't find a reason for the issue. Since this worked when sitecore role is set to "ContentManagement" role, debug or finding actual reason made much harder.

Finally we contacted Sitecore Support and they were able to find the reason for this.

According to Sitecore Support, there is a code deadlock scenario when EXM & FXM used together in Sitecore 9 versions.

Issue :
When the Sitecore role set to "ContentDelivery" in app settings, initial page request for the front-end site takes 15-30 minutes time to load.
Some have experience this same scenario on ContentManagement role as well as running on "Standalone" role.

Fix :

Sitecore.Support.329897.config
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <hooks>
<hook type="Sitecore.Owin.Authentication.Pipelines.CookieAuthentication.ValidateIdentity.CheckIdentityProvider, Sitecore.Owin.Authentication" resolve="true" patch:before = "*[1]" />
</hooks>
  </sitecore>
</configuration>


NOTE: This fix is a temporarily fix where it tries to find the erroneous request earlier in the request pipeline and will throw an error onto the logs once that captured.

Example Error on logs after this patch:

ERROR Hook object does not implement IHook. Config node: <hook type="Sitecore.Owin.Authentication.Pipelines.CookieAuthentication.ValidateIdentity.CheckIdentityProvider, Sitecore.Owin.Authentication" resolve="true" patch:source="Sitecore.Support.329897.config" xmlns:patch="http://www.sitecore.net/xmlconfig/" /> (method: Sitecore.Events.Hooks.HookManager.LoadAll()).
11020 11:52:51 ERROR Error loading hook: <hook type="Sitecore.Owin.Authentication.Pipelines.CookieAuthentication.ValidateIdentity.CheckIdentityProvider, Sitecore.Owin.Authentication" resolve="true" patch:source="Sitecore.Support.329897.config" xmlns:patch="http://www.sitecore.net/xmlconfig/" />
Exception: System.Exception
Message: Hook object does not implement IHook. Config node: <hook type="Sitecore.Owin.Authentication.Pipelines.CookieAuthentication.ValidateIdentity.CheckIdentityProvider, Sitecore.Owin.Authentication" resolve="true" patch:source="Sitecore.Support.329897.config" xmlns:patch="http://www.sitecore.net/xmlconfig/" /> (method: Sitecore.Events.Hooks.HookManager.LoadAll()).
Source: Sitecore.Events.Hooks.HookManager.LoadAll()

According to Sitecore Support, this issue should be patched/fixed with upcoming Sitecore 9.3 release

Thursday, September 5, 2019

Sitecore 9 Identity Server Error With CA SSL Certificates

One of the implementations I did recently is a Sitecore 9.1 installation/upgrade.

Initially we had the Sitecore Identity server IIS site running using a Self-Signed certificate and I adjusted it to be using CA signed SSL certificate.

That was done by importing that certs .pfx file into Trusted Root Certificate section of the Local Computer cert store, using MMC.
Then adjusted the Sitecore Identity server settings and Sitecore instance setting to match that certificate location & its certificate key. Also adjusted IIS site instance to use this newly imported certificate.

Once the above is done, we started to face issues with Sitecore logins. We were not able to get the Sitecore login working with Identity Server instance returning 500 error message.

[FTL] (Sitecore STS/auenws-sccm-w01) Unhandled exception: "Keyset does not exist"
Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: Keyset does not exist
   at Internal.NativeCrypto.CapiHelper.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)
   at System.Security.Cryptography.RSACryptoServiceProvider.get_SafeProvHandle()
   at System.Security.Cryptography.RSACryptoServiceProvider.get_SafeKeyHandle()
   at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 keySize, CspParameters parameters, Boolean useDefaultKeySize)
   at System.Security.Cryptography.RSACryptoServiceProvider..ctor(CspParameters parameters)
   at Internal.Cryptography.Pal.CertificatePal.<>c.<GetRSAPrivateKey>b__61_0(CspParameters csp)
   at Internal.Cryptography.Pal.CertificatePal.GetPrivateKey[T](Func`2 createCsp, Func`2 createCng)
   at Internal.Cryptography.Pal.CertificatePal.GetRSAPrivateKey()
   at Internal.Cryptography.Pal.CertificateExtensionsCommon.GetPrivateKey[T](X509Certificate2 certificate, Predicate`1 matchesConstraints)
   at Microsoft.IdentityModel.Tokens.X509SecurityKey.get_PrivateKey()
   at Microsoft.IdentityModel.Tokens.X509SecurityKey.get_PrivateKeyStatus()
   at Microsoft.IdentityModel.Tokens.AsymmetricSignatureProvider..ctor(SecurityKey key, String algorithm, Boolean willCreateSignatures)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.CreateEncodedSignature(String input, SigningCredentials signingCredentials)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.WriteToken(SecurityToken token)
   at IdentityServer4.Services.DefaultTokenCreationService.CreateJwtAsync(JwtSecurityToken jwt)
   at IdentityServer4.Services.DefaultTokenCreationService.CreateTokenAsync(Token token)
   at IdentityServer4.Services.DefaultTokenService.CreateSecurityTokenAsync(Token token)
   at IdentityServer4.ResponseHandling.AuthorizeResponseGenerator.CreateImplicitFlowResponseAsync(ValidatedAuthorizeRequest request, String authorizationCode)
   at ......

Then what I did was searching the internet for the above error message.

The solution that was provided by the to people was to set the permission on the imported certificate for the IIS app user account.

To achieve that, we need to be able to access the "All Tasks -> Manage Private Keys..." option for that certificate.




But that option was not available when the certificate is on the "Trusted Root Certification Authorities" OR "Intermediate Certification Authorities". But that option is only available for certificates on "Personal" certificate store.

So what I did was,
1) I moved our imported certificate from "Trusted Root Certification Authories" store to "Personal" store.
2) Then set the permission for "IIS_IUSRS" user for that certificate using "Manage Private Keys..." option.
3) Then moved back the certificate again to "Trusted Root Certification Authorities" store.

(info on https://stackoverflow.com/questions/12106011/system-security-cryptography-cryptographicexception-keyset-does-not-exist)

This solved the issues with the Sitecore login.

Happy Sitecore!!


Monday, July 29, 2019

Glass Mapper StackOverflow Memory exception with InferType property set to Disable Lazy Loading

Recently we upgraded one of our solutions to Sitecore 9.1 and Glass Mapper 5.

After the upgrade, with some custom code also added, we started to get an issue with the Glass Mapper implemented solution, where the front-end website just throw an error and just dies. We were able to login to Backend Sitecore without any issues.

Following popup message is the only thing we get and site just throw this error continuously until we do an IIS reset.

Front-End Website Error Popup



There were nothing in the Sitecore Logs too related to this error.

But we could see following error on Windows event logs, which does not provide any useful information.

Faulting application name: w3wp.exe, version: 10.0.17134.1, time stamp: 0xed729d4eFaulting module name: clr.dll, version: 4.7.3416.0, time stamp: 0x5cabfc63Exception code: 0xc00000fdFault offset: 0x00000000000f503fFaulting process ID: 0x35b4Faulting application start time: 0x01d53db16c6f9a75Faulting application path: c:\windows\system32\inetsrv\w3wp.exeFaulting module path: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dllReport ID: a175fc77-b1fd-4370-bee8-f2dd927f34daFaulting package full name:


So, we go a memory dump and was able to see following error was thrown with StackOverflow exception. This below error was throwing over and over again.
.........Glass.Mapper.Sc.SitecoreService.RunCreateType(Sitecore.Data.Items.Item, Glass.Mapper.GetOptions, System.Collections.Generic.Dictionary`2<System.String, System.Object>)Glass.Mapper.Sc.LazyItemEnumerable`1[[System.__Canon, mscorlib]].ProcessItems()mscorlib_ni!System.Lazy`1[System.__Canon].CreateValue()$##6000F19+ecmscorlib_ni!System.Lazy`1[System.__Canon].LazyInitValue()$##6000F18+b8Glass.Mapper.Sc.LazyItemEnumerable`1[[System.__Canon, mscorlib]]..ctor(Glass.Mapper.Sc.GetItemsOptions, Glass.Mapper.Sc.ISitecoreService, Glass.Mapper.LazyLoadingHelper)DynamicClass.lambda_method(System.Runtime.CompilerServices.Closure, System.Object[])Glass.Mapper.Utilities.CreateGenericType(System.Type, System.Type[], System.Object[])Glass.Mapper.Sc.SitecoreService.GetItems(Glass.Mapper.Sc.GetItemsOptions)Glass.Mapper.AbstractDataMapper.MapCmsToProperty(Glass.Mapper.AbstractDataMappingContext)Glass.Mapper.Configuration.AbstractTypeConfiguration.MapPropertiesToObject(System.Object, Glass.Mapper.IAbstractService, Glass.Mapper.AbstractTypeCreationContext)Glass.Mapper.Pipelines.ObjectConstruction.Tasks.CreateConcrete.CreateConcreteTask.CreateObjectAndMapProperties(Glass.Mapper.Pipelines.ObjectConstruction.ObjectConstructionArgs)Glass.Mapper.Pipelines.ObjectConstruction.Tasks.CreateConcrete.CreateConcreteTask.Execute(Glass.Mapper.Pipelines.ObjectConstruction.ObjectConstructionArgs)Glass.Mapper.Pipelines.AbstractPipelineTask`1[[System.__Canon, mscorlib]].Next(System.__Canon)Glass.Mapper.Sc.Pipelines.ObjectConstruction.EnforcedTemplateCheck.PerformTemplateCheck(Glass.Mapper.Pipelines.ObjectConstruction.ObjectConstructionArgs, Sitecore.Data.ID, Glass.Mapper.Sc.Configuration.SitecoreEnforceTemplate)Glass.Mapper.Pipelines.AbstractPipelineTask`1[[System.__Canon, mscorlib]].Next(System.__Canon)Glass.Mapper.Pipelines.ObjectConstruction.Tasks.CacheCheck.CacheCheckTask.Execute(Glass.Mapper.Pipelines.ObjectConstruction.ObjectConstructionArgs)Glass.Mapper.Pipelines.AbstractPipelineTask`1[[System.__Canon, mscorlib]].Next(System.__Canon)Glass.Mapper.Sc.Pipelines.ObjectConstruction.SitecoreItemTask.Execute(Glass.Mapper.Pipelines.ObjectConstruction.ObjectConstructionArgs)Glass.Mapper.Pipelines.AbstractPipelineTask`1[[System.__Canon, mscorlib]].Next(System.__Canon)Glass.Mapper.Pipelines.AbstractPipelineTask`1[[System.__Canon, mscorlib]].Next(System.__Canon)Glass.Mapper.Sc.Pipelines.ObjectConstruction.NullItemTask.Execute(Glass.Mapper.Pipelines.ObjectConstruction.ObjectConstructionArgs)Glass.Mapper.Pipelines.AbstractPipelineRunner`2[[System.__Canon, mscorlib], [System.__Canon, mscorlib]].Run(System.__Canon)Glass.Mapper.AbstractService.InstantiateObject(Glass.Mapper.AbstractTypeCreationContext)Glass.Mapper.Sc.SitecoreService.RunCreateType(Sitecore.Data.Items.Item, Glass.Mapper.GetOptions, System.Collections.Generic.Dictionary`2<System.String, System.Object>)Glass.Mapper.AbstractDataMapper.MapCmsToProperty(Glass.Mapper.AbstractDataMappingContext)Glass.Mapper.Configuration.AbstractTypeConfiguration.MapPropertiesToObject(System.Object, Glass.Mapper.IAbstractService, Glass.Mapper.AbstractTypeCreationContext)Glass.Mapper.Pipelines.ObjectConstruction.Tasks.CreateConcrete.CreateConcreteTask.CreateObjectAndMapProperties(Glass.Mapper.Pipelines.ObjectConstruction.ObjectConstructionArgs)Glass.Mapper.Pipelines.ObjectConstruction.Tasks.CreateConcrete.CreateConcreteTask.Execute(Glass.Mapper.Pipelines.ObjectConstruction.ObjectConstructionArgs)Glass.Mapper.Pipelines.AbstractPipelineTask`1[[System.__Canon, mscorlib]].Next(System.__Canon)Glass.Mapper.Sc.Pipelines.ObjectConstruction.EnforcedTemplateCheck.PerformTemplateCheck(Glass.Mapper.Pipelines.ObjectConstruction.ObjectConstructionArgs, Sitecore.Data.ID, Glass.Mapper.Sc.Configuration.SitecoreEnforceTemplate)Glass.Mapper.Pipelines.AbstractPipelineTask`1[[System.__Canon, mscorlib]].Next(System.__Canon)Glass.Mapper.Pipelines.ObjectConstruction.Tasks.CacheCheck.CacheCheckTask.Execute(Glass.Mapper.Pipelines.ObjectConstruction.ObjectConstructionArgs)Glass.Mapper.Pipelines.AbstractPipelineTask`1[[System.__Canon, mscorlib]].Next(System.__Canon)Glass.Mapper.Sc.Pipelines.ObjectConstruction.SitecoreItemTask.Execute(Glass.Mapper.Pipelines.ObjectConstruction.ObjectConstructionArgs)Glass.Mapper.Pipelines.AbstractPipelineTask`1[[System.__Canon, mscorlib]].Next(System.__Canon)Glass.Mapper.Pipelines.AbstractPipelineTask`1[[System.__Canon, mscorlib]].Next(System.__Canon)Glass.Mapper.Sc.Pipelines.ObjectConstruction.NullItemTask.Execute(Glass.Mapper.Pipelines.ObjectConstruction.ObjectConstructionArgs)Glass.Mapper.Pipelines.AbstractPipelineRunner`2[[System.__Canon, mscorlib], [System.__Canon, mscorlib]].Run(System.__Canon)Glass.Mapper.AbstractService.InstantiateObject(Glass.Mapper.AbstractTypeCreationContext)Glass.Mapper.Sc.SitecoreService.RunCreateType(Sitecore.Data.Items.Item, Glass.Mapper.GetOptions, System.Collections.Generic.Dictionary`2<System.String, System.Object>)Glass.Mapper.Sc.SitecoreService.GetItem[[System.__Canon, mscorlib]](Glass.Mapper.Sc.GetItemOptions) ................

After few days of investigation, we were lucky enough to see some code part in our solution that might caused this. It was actually a LazyLoad setting setup for InferType properties in the base Glass model. From our code, we have disabled LazyLoading for InterType which caused the Glass Mapper to load all the parent/children items for Parents/Children InferType property defined in the Glass Base mode.

public GetItemByIdOptions CreateGetItemByIdOptions(Guid id) => new GetItemByIdOptions(id) { InferType = true, Lazy = Glass.Mapper.LazyLoading.Disabled };

Once we adjusted that "Lazy" setting to "Enabled" (see below), site starts to load without any issue again.


public GetItemByIdOptions CreateGetItemByIdOptions(Guid id) => new GetItemByIdOptions(id) { InferType = true, Lazy = Glass.Mapper.LazyLoading.Enabled };

Special thanks for Kamruz Jaman & Mike Renolds in Sitecore community to helping out with this issue with suggestions and time.


Hope this will help someone.. :-)


References :
This should be another reason for your Sitecore 9 site not loading - https://medium.com/@markgibbons25/sitecore-crashing-on-startup-with-internal-error-in-the-net-runtime-be5831e94b6e


Happy Sitecore!!!















Saturday, July 6, 2019

Sitecore User Group Conference - India - 2019

SUGCON India was held for the second consecutive year in this year (2019) at Bengaluru, India. This years event was held at ITC Gardenia hotel, Bengaluru and was a success with more than 200 participated.




I had the opportunity to conduct the Sitecore JSS workshop at the Sitecore User Group Conference India 2019. 30 people participated for this JSS workshop organized by Sitecore as pre-event classroom training. Special thanks to Pieter Brinkman & Rob Earlam from Sitecore for giving me the opportunity to conduct this JSS workshop on behalf of Sitecore. I hope participants walk away with good understanding of Sitecore JSS.




Also I had the opportunity of presenting my findings & experience on Sitecore SXA. Topic of the talk was "Accelerate your Sitecore website delivery with Sitecore SXA" and hope participants got motivation after seeing the website time-to-deliver got reduced dramatically using Sitecore SXA.


Presentation Slides : https://www.slideshare.net/chaturangaranatunga/accelerate-your-sitecore-website-delivery-with-sitecore-sxa-sugcon-india-2019
Presentation Recording : https://www.youtube.com/watch?v=D9oGYdANBN4&list=PLFwvXROgXsHMcp3KWefRIQSQMdTn0YIe0&index=27&t=0s


During the award ceremony held at the conclusion of the event, I receive my Sitecore Technology MVP 2019 award from Pieter Brinkman (Senior Director - Sitecore Technical Marketing). I thank Sitecore & Sitecore Technocal Marketing Team for the continuous help/encouragement provided for the community.

This is my 4th consecutive Sitecore Technology MVP award starting from year 2016.

Photo Credit : SUGCON India 2019 Website


I was interviewed by Sitecore for a Media bites session and following is its recording.



Overall it was a great event with meeting lots of community friends and lots and lots of knowledge sharing.

Hoping to see you all in next year's SUGCON India.



References:

SUGCON India Website : https://www.sugcon.in/
My Media bites interview : https://www.youtube.com/watch?v=lJFujE3J-RA&list=PLFwvXROgXsHM7Kh_64DSS_CXHOEka_Pb1&index=10
All the presentations slides : https://www.sugcon.in/2019-home/session-slides/
All the presentations recordings : https://www.youtube.com/playlist?list=PLFwvXROgXsHMcp3KWefRIQSQMdTn0YIe0
All the media from the event : https://www.sugcon.in/2019-home/media/





Wednesday, May 22, 2019

Make Sitecore SXA Sitemap Generation Respect SiteLanguages Setting

Recently we faced an issue where Sitecore SXA Sitemap is not respecting the Languages selected from the "Site Languages" field in site settings item.


For example, say you have a SXA site with "en-GB" selected as the Site Language in the settings. (see image below).



But  if an item have "en" language item also, generated sitemap will contain "hreflang" entries for both "en-GB" and "en" languages. (see image below)



So I decoded the Sitecore.XA.Feature.SiteMetadata.dll and in the "BuildMultilanguageSitemap" method, it's taking all the languages of the item and adding "hreflang" for each of those languages.
As you can see in the below image, it doesn't consider "Site Languages" setting set in the "Settings" item.




public class SitemapGenerator : Sitecore.XA.Feature.SiteMetadata.Sitemap.SitemapGenerator
{
    {
        private _MultiLanguageSettings _multiLanguageSettings;

        public SitemapGenerator() : base()
        {
            _multiLanguageSettings = ServiceLocator.ServiceProvider.GetService<IMultiLanguageRepository>().GetMultiLanguageSettings(Sitecore.Context.Site);
        }

        protected override StringBuilder BuildMultilanguageSitemap(IEnumerable<Item> childrenTree, SitemapLinkOptions options)
        {
            UrlOptions urlOptions = this.GetUrlOptions();
            SitemapLinkOptions options1 = new SitemapLinkOptions(options.Scheme, urlOptions, options.TargetHostname);
            List<XElement> xelementList1 = new List<XElement>();
            StringBuilder stringBuilder = new StringBuilder();

            if (_multiLanguageSettings == null || _multiLanguageSettings.SiteLanguages == null || !_multiLanguageSettings.SiteLanguages.Any())
            {
                return stringBuilder;
            }

            foreach (Item item in childrenTree)
            {
                SitemapChangeFrequency sitemapChangeFrequency = item.Fields[Sitecore.XA.Feature.SiteMetadata.Templates.Sitemap._Sitemap.Fields.ChangeFrequency].ToEnum<SitemapChangeFrequency>();

                if (sitemapChangeFrequency != SitemapChangeFrequency.DoNotInclude)
                {
                    List<XElement> xelementList2 = new List<XElement>();

                    foreach (Language language in item.Languages)
                    {
                        if (!_multiLanguageSettings.SiteLanguages.Any(l => l.Name.Equals(language.Name, StringComparison.InvariantCultureIgnoreCase)))
                        {
                            continue;
                        }

                        Item langItem = item.Database.GetItem(item.ID, language);
                        if (langItem.Versions.Count > 0)
                        {
                            options1.UrlOptions.Language = language;
                            XElement xelement = this.BuildAlternateLinkElement(this.GetFullLink(langItem, options1), language.CultureInfo.Name, "alternate");
                            xelementList2.Add(xelement);
                        }
                    }

                    options1.UrlOptions.Language = item.Language;
                    XElement xelement1 = this.BuildPageElement(this.GetFullLink(item, options1), this.GetUpdatedDate(item), sitemapChangeFrequency.ToString().ToLower(), this.GetPriority(item), (IEnumerable<XElement>)xelementList2);
                    xelementList1.Add(xelement1);
                }
            }

            XDocument xdocument = this.BuildXmlDocument((IEnumerable<XElement>)xelementList1);

            using (TextWriter textWriter = (TextWriter)new StringWriter(stringBuilder))
            {
                xdocument.Save(textWriter);
            }

            this.FixDeclaration(stringBuilder);
            return stringBuilder;
        }
}


Hope this helps !!!