Sitecore Experience Platform 10 is out and as part of Sitecore community as well as a Sitecore developer I am happy so see all the new developer-focused changes in the product. One of the biggest changes that I have been waiting for a long time is the proper serialization implementation.

Since I first met Sitecore in version 6 I have tried all kinds of different approaches in sharing the developer-controlled Sitecore items such as Templates, Renderings etc:

  • Shared development master database
  • Storing sitecore packages per feature
  • TDS serialization
  • Unicorn serialization

In my opinion the most effective, developer-friendly and consistent tool appeared to to be Unicorn. The .yaml format has been proven to be much more efficient then original .item serrialization implementation. However, I always thought that the platform itself should have something similar out of the box. And now this time has come!

Meet and greet Sitecore Content Serialization. Together with the Sitecore Command Line interface it opens up pretty much all developer capabilities that we had with the Unicorn.

In this post I will try to cover the whole development cycle but with using the new Sitecore Content Serialization instead of the Unicorn.

Prerequisites

In order to get started we will need to:

Configuring serialization within helix architecture

First thing we would need to do is to declare the global variables and some manifest in order to let the serializer to know where to look for the serialization incliudes.
After you run the init command from the Sitecore CLI for your project along with the other files, you will see the sitecore.json file where these things are configured:

{
  "$schema": "./.sitecore/schemas/RootConfigurationFile.schema.json",
  "modules": [
    "./src/*/*/code/.modules/*.module.json"
  ],
  "serialization": {
    "defaultMaxRelativeItemPathLength": 130,
    "defaultModuleRelativeSerializationPath": "../../serialization"
  }
}

The “modules” property is the pattern collection on how the serializer should find all our helix projects serialization includes. In this example I declared that for example my Feature module would have a file with extension “.module.json” on a path like “/src/Feature/Metadata/code/.modules/Feature.Metadata.module.json”.
In orher words the serializer will find all those .module.json files depending on how we declare the patterns to their paths and how we store them in the solution. The example if the .module.json file would look like this:

{
	"namespace": "Feature.Metadata",
	"references": [ "*Foundation.*" ],
	"items": {
		"includes": [
			{
				"name": "Templates",
				"path": "/sitecore/templates/Feature/Metadata"
			},
			{
				"name": "Renderings",
				"path": "/sitecore/layout/Renderings/Feature/Metadata"
			}
		]
	}
}

Looks familiar right? We have seen it before. And that is because the Sitecore Content Serialization have been heavily inspired by Unicorn principles and implementation. We can find all kinds of inclusion rules for particular paths in the documentation here. Roughly, I have an impression that now we have more flexibility in the SCS rules than the Unicorn provides us with its own inclusion rules.

Development workflow on working with Sitecore CLI serialization commands

With Unicorn, while developing a feature, we have had a workflow which would reside in next actions:

  • Develop your templates/renderings etc.
  • Serialize your items to source control. (normally happens automatically for us)
  • Get latest version, run “Sync all the things” with Unicorn
  • Commit and push your changes to the source control

And now, with the Sitecore Content Serialization we would have something similar, but instead of unicorn panel we would use the Sitecore CLI:

  • Develop your templates/renderings etc.
  • Serialize your items to source control. Execute CLI command: ‘dotnet sitecore ser pull’
  • Get latest version, Execute CLI command: ‘dotnet sitecore ser push’
  • Commit and push your changes to the source control

In orher words the process is the same, just interface and commands have changed.


Along with pull/push commands, Sitecore CLI gives us more functionality which is well documented here.

SCS yaml format vs Unicorn yaml format

This topic probably deserves a separate blogpost, however I have had a brief look and here is what I discovered.

  • I have tried to serialize the items with SCS and try to read with Unicorn’s Rainbos serializer. This did not work for me.
  • However, I have tried to do vice-versa. I took the unicorn-serialiezed folder and have put it under my SCS-controlled directory. And that has magically worked! This tells a lot to me. For example, migrating the project from Unicorn to the SCS would be not that hard of a task. The only thing that we might have problems dealing with is the calculation of the new “defaultMaxRelativeItemPathLength” value as Unicorn has its own variable for that and we may need to re-calculate it depending on how both systems get the start point.

Lets take same Item and serialize it with both Unicorn and SCS and see what was actually serialized.
So the Uniocorn has produced me next file: _Navigation.yaml

---
ID: "0f8c46c4-e777-46d0-89e0-225972998022"
Parent: "8f168ea5-ee4c-4ab8-a8c7-bb8436f081b0"
Template: "ab86861a-6030-46c5-b394-e8f99e8b87db"
Path: /sitecore/templates/Feature/Navigation/Data/_Navigation
DB: master
SharedFields:
- ID: "12c33f3f-86c5-43a5-aeb4-5598cec45116"
  Hint: __Base template
  Type: tree list
  Value: "{1930BBEB-7805-471A-A3BE-4858AC7CF696}"
- ID: "f7d48a55-2158-4f02-9356-756654404f73"
  Hint: __Standard values
  Value: "{44A0BA74-0D79-4A04-804F-DC3A8F7A083B}"
- Language: en
  Versions:
  - Version: 1
    Fields:
    - ID: "25bed78c-4957-4165-998a-ca1b52f67497"
      Hint: __Created
      Value: 20190319T123232Z

And the Sitecore Content Serialization gives me next _Navigation.yaml file:

---
ID: "0f8c46c4-e777-46d0-89e0-225972998022"
Parent: "8f168ea5-ee4c-4ab8-a8c7-bb8436f081b0"
Template: "ab86861a-6030-46c5-b394-e8f99e8b87db"
Path: /sitecore/templates/Feature/Navigation/Data/_Navigation
SharedFields:
- ID: "12c33f3f-86c5-43a5-aeb4-5598cec45116"
  Hint: __Base template
  Value: "{1930BBEB-7805-471A-A3BE-4858AC7CF696}"
- ID: "f7d48a55-2158-4f02-9356-756654404f73"
  Hint: __Standard values
  Value: "{44A0BA74-0D79-4A04-804F-DC3A8F7A083B}"
Languages:
- Language: en
  Versions:
  - Version: 1
    Fields:
    - ID: "25bed78c-4957-4165-998a-ca1b52f67497"
      Hint: __Created
      Value: 20190319T123232Z
    - ID: "8cdc337e-a112-42fb-bbb4-4143751e123f"
      Hint: __Revision
      Value: "20608d79-8711-4426-9656-e6610edc5476"
    - ID: "badd9cf9-53e0-4d0c-bcc0-2d784c282f6a"
      Hint: __Updated by
      Value: |
        sitecore\unicorn
    - ID: "d9cf14b1-fa16-4ba6-9288-e8a174d4d522"
      Hint: __Updated
      Value: 20190507T140938Z

Almost same right? We can notice that the database name is not being included into SCS yaml format, and that is probably why the Rainbow did not want to work for me. Also there are few additional fields that are getting serialized by default with the SCS, however that should not cause any issues in the migration projects.

Code generation with Sitecore Content Serialization

This indeed the big topic and deserves a separate post. Briefly, I have managed to implement code generation using .tt files and native Sitecore Content Serialization.
In order to do that, we need to use the native Sitecore.Data.Serialization.Yaml.YamlItemSerializer class. The implementation of this has a constructor dependency on the
Sitecore.Data.Serialization.Yaml.Formatting.FieldFormattersFactory, wich also has a dependency on Sitecore.Abstractions.BaseFactory.

Obviously, within the .tt file we have no Sitecore context and can not get any access to the instance configuration. So what I did was:

  • Implemented MockedConfigurationFactory, which just implements the BaseFactory but does nothing.
  • Implemented a stub-class StaticFieldFormattersFactory which inherits the FieldFormattersFactory and instead of reading the config, just returns list of formatters we specify to it.
  • With having those actions above I can instantiate the Sitecore.Data.Serialization.Yaml.YamlItemSerializer class and read the templates in my SCS serialized folders
public virtual IEnumerable<TemplateData> GetTemplateData()
{
	var files = this.pathsToTemplates.SelectMany(x => Directory.EnumerateFiles(x, "*.yml", SearchOption.AllDirectories));
	var items = new List<IItemData>();

	var factory = new StaticFieldFormattersFactory(this.fieldFormatters);
	var serializer = new YamlItemSerializer(factory);
	
	foreach (var file in files)
	{
		using (TextReader reader = new StreamReader(file))
		{
			var item = serializer.Read(reader);
			items.Add(item);
		}
	}

	var itemsLookup = items.ToLookup(x => x.ParentId, x => x);

	var templates = items
		.Where(x => x.TemplateId == Sitecore.TemplateIDs.Template.Guid);

	return templates.Select(template => new TemplateData
	{
		Template = template,
		Fields = this.GetFields(template.Id, itemsLookup)
	});
}

and the usage from the .tt file would be:

<# 
// default formatters set from Sitecore 10 initial release, check <fieldFormatters> configuration node in your Sitecore instance.
var formatters = new BaseFieldFormatter[]
{
	new XmlFieldFormatter(),
	new MultilistFormatter(),
	new CheckboxFieldFormatter()
};
var gen = new SitecoreCodeGenerator(Configurations, formatters);

foreach (var data in gen.GetTemplateData()) 
{ 
	var template = data.Template; 
	var fields = data.Fields;
#>
... transformations here ...
<# } #>

I have implemented the working code-generation for xWrap framework item wrappers, please find the code on my github here

As a conclusion, I have managed to do almost everything that we normally do with the Unicorn in a standard scenarios, I can clearly see how the developer process would look like with the SCS instead of the Unicorn. The only thing that I did not figure out here is how to serialize Users/Roles with SCS.

Share article
See also

Changes to link generation in Sitecore 9.3

Read more Volodymyr Hil 16.04.2020
Sitecore do not copy

Sitecore item copy extensions

Read more Volodymyr Hil 12.12.2019
Pintle.Packager – Sitecore Package Generator

Pintle.Packager – Sitecore Package Generator

Read more Volodymyr Hil 07.10.2019

MVC renderings with xWrap framework – Sitecore Experience Wrapper

Read more Volodymyr Hil 10.12.2018

Introducing xWrap framework – Sitecore Experience Wrapper

Read more Volodymyr Hil 09.12.2018