Sitecore CLI and content migration from 8.2 to 10.2

During one of the many Sitecore upgrades this year (to Sitecore version 10.2), I participated in a team of developers where one of the developers strongly wanted a specific strategy for moving content from the old solution into the new Sitecore 10.2 vanilla solution (instead of using Sitecore standard upgrade scripts/wizard for migrating/upgrading databases).


The implemented solution was a history/result of previously different upgrades with different item serialization implementations (both unicorn and TDS was in use at the same time - making it hard for developers to manage items to be serialized to code repo for deployment etc). 


The process was decided to be an installation of Sitecore CLI in a vanilla Sitecore 10.2 solution, but attaching the source databases of the Sitecore 8.2 solution containing the content to be serialized - templates, layout ref. items etc. Then move the Sitecore CLI *.module.json files and serialized items (all the *.yml files) from the vanilla Sitecore 10.2 solution to the code upgraded solution in the respective Helix folder structures, and then after that serialize all the items into the new upgraded Sitecore solution (no comments on this process... tsk, tsk).


Anyway, the source Sitecore 8.2 solution contained customization in the core database (for custom commands in the Content Editor ribbon etc.). As I initially tried to install the Sitecore CLI in the vanilla Sitecore 10.2 solution but attached with Sitecore 8.2 databases, I was not able to log into the Sitecore client (by trying to login to Sitecore client via Sitecore CLI for serializing items). I got the following error in powershell: 




And the Sitecore client:


The Identity Server log stated: 

Error Number:208,State:1,Class:16"

Microsoft.Data.SqlClient.SqlException (0x80131904): Invalid object name 'PersistedGrants'.

   at Microsoft.Data.SqlClient.SqlCommand.<>c.<ExecuteDbDataReaderAsync>b__164_0(Task`1 result)

   at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()

   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)

--- End of stack trace from previous location where exception was thrown ---

   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)

--- End of stack trace from previous location where exception was thrown ---

   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)

   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)

   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)

   at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.AsyncEnumerator.InitializeReaderAsync(DbContext _, Boolean result, CancellationToken cancellationToken)

   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)

   at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()

ClientConnectionId:10e2a893-524b-442c-9cea-6a4fbc67be9f

Error Number:208,State:1,Class:16


Stated that a PersistantGrants table in the Sitecore 8.2 core database was missing (the PersistedGrants table was introduced in Sitecore 10) - used by the IdentityServer4. 

By adding the table into the source Sitecore 8.2 Core database using: 


USE [Customer.Sitecore.Core] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[PersistedGrants] (
[Key] nvarchar(200) NOT NULL,
[Type] nvarchar(50) NOT NULL,
[SubjectId] nvarchar(200) NULL,
[SessionId] nvarchar(100) NULL,
[ClientId] nvarchar(200) NOT NULL,
[Description] nvarchar(200) NULL,
[CreationTime] datetime2 NOT NULL,
[Expiration] datetime2 NULL,
[ConsumedTime] datetime2 NULL,
[Data] nvarchar(max) NOT NULL,
CONSTRAINT [PK_PersistedGrants] PRIMARY KEY ([Key])
);

The table was added. But then leaving to the next missing table (stated in a log error similar to the one above for the missing PersistedGrants table). The DeviceCodes. Once again adding the DeviceCodes table:

USE [Customer.Sitecore.Core] GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [DeviceCodes] (
[UserCode] nvarchar(200) NOT NULL,
[DeviceCode] nvarchar(200) NOT NULL,
[SubjectId] nvarchar(200) NULL,
[SessionId] nvarchar(100) NULL,
[ClientId] nvarchar(200) NOT NULL,
[Description] nvarchar(200) NULL,
[CreationTime] datetime2 NOT NULL,
[Expiration] datetime2 NOT NULL,
[Data] nvarchar(max) NOT NULL,
CONSTRAINT [PK_DeviceCodes] PRIMARY KEY ([UserCode])
);

After that, the tables was created, and the Sitecore CLI could log into the Sitecore Client, and I could continue serializing the customization made in the Sitecore 8.2 core database...

Sitecore and client time out

So some month ago I had a customer that was contacted by Sitecore (version 10.2), because of heavy use of Sitecore user boosting (you know, when the limit of concurrent users has been reached - the one trying to login can boost the number of concurrent users. Typically by boosting five more temp users). 


As the customer didn't have more content "contributors" (editors, marketers, admins etc) working in the client, than the number of concurrent users in the license subscribed, the issue was not because of incorrect license, but more of contributors not logging out or correctly. 


After changing the session timeout in the /App_Config/Sitecore.config file from two hours (it was an old change and the customer was one handed over by another Sitecore implementation partner) to 20 minutes:


<!--  AUTHENTICATION CLIENT SESSION TIMEOUT
    Specifies the number of minutes before Sitecore considers user authentication session tickets as expired.
    This setting is only relevant for users logging in to Sitecore Client and when the Sitecore license has a limited number
    of concurrent editors. 
    All expired sessions will automatically be removed when a new user tries to log in and the maximum
    number of concurrent editors has been reached. 
    The default is 60 minutes (1 hour).
--> 

<setting name="Authentication.ClientSessionTimeout" value="20" />


We still had the issue with exceeding the number of concurrent users. As the customer was using Sitecore Identity and Sitecore Identity Server the user at the Sitecore Identity Server was still active. But by aligning the Sitecore Identity Server session timeout / accesstoken/identitytoken lifetime with the Authentication client session timeout, the content contributor was correctly logged out after 20 minutes of idle  - making the use of Sitecore User Boosting much rare.