Serializing rendering parameters in the layout service

The Layout Service currently has limited support for rendering parameters. Parameters are output as name:value pairs which means if you use something like a DropLink as a lookup (e.g. classes, colours, padding or whatever) for rendering parameters then you just get the ID of the item being referenced.

As an example, I’ve created a rendering parameters template for the “Featured Blogs” rendering, which has a single field “Category”, intended to filter blogs being listed to a specific category:

The rendering has been added to the Blog Home page Final Layout and a value set for the Category:

However, out of the box the Layout Service will return the following:

which in some cases might be what you need, but what if you need the target item to which the Droplink field refers? e.g. a CSS class string from a reference data item stored in your site Data folder.

The solution is to override the Initialize pipeline processor in Sitecore.LayoutService.Presentation.Pipelines.RenderJsonRendering and patch it into the Layout Service pipeline configuration.

Patching the Layout Service pipeline processor

Overriding the Initialize method of RenderJsonRendering allows us to extend the RenderingParams property in the RenderedJsonRendering object returned by the pipeline processor with serialized values instead of actual values. (Credit to Jason Woods and the Sitecore Product Team for pointing the way on this one)

using System.Collections.Generic;
using Sitecore.Data;
using Sitecore.Data.Items;
using Sitecore.LayoutService.Configuration;
using Sitecore.LayoutService.ItemRendering;
using Sitecore.LayoutService.Presentation.Pipelines.RenderJsonRendering;
using Sitecore.LayoutService.Serialization;
using Sitecore.Mvc.Presentation;
using System.Linq;

namespace JSSDemo.Foundation.LayoutService.PipelineProcessors
{
    public class CustomInitialize : Initialize
    {
        IRenderingConfiguration _renderingConfiguration;

        public CustomInitialize(IConfiguration configuration) : base(configuration) { }

        protected override RenderedJsonRendering CreateResultInstance(RenderJsonRenderingArgs args)
        {
            _renderingConfiguration = args.RenderingConfiguration;

            //Note: the constructor below is different for Sitecore 9.x and 10. The below will only work in Headless Services for Sitecore 10.
            return new RenderedJsonRendering()
            {
                Name = args.Rendering.RenderingItem.Name,
                DataSource = args.Rendering.DataSource,
                RenderingParams = SerializeRenderingParams(args.Rendering),
                Uid = args.Rendering.UniqueId
            };
        }

        protected virtual IDictionary<string, string> SerializeRenderingParams(Rendering rendering)
        {
            IDictionary<string, string> paramDictionary = rendering.Parameters.ToDictionary(pair => pair.Key, pair => pair.Value);
            foreach (string key in paramDictionary.Keys.ToList())
            {
                if (ID.TryParse(paramDictionary[key], out var itemId))
                {
                    Item item = rendering.RenderingItem.Database.GetItem(itemId);
                    paramDictionary[key] = _renderingConfiguration.ItemSerializer.Serialize(item, new SerializationOptions() { DisableEditing = true });
                }
            }
            return paramDictionary;
        }
    }
}

This is then patched into the LayoutService renderJsonRendering pipeline:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <group groupName="layoutService">
		  <!-- NOTE: This patch will be have a slightly different signature in Headless Services for Sitecore 9.x vs 10. The below works for Headless Services in Sitecore 10 -->
		  <pipelines>
			  <renderJsonRendering>
				  <processor type="JSSDemo.Foundation.LayoutService.PipelineProcessors.CustomInitialize, JSSDemo.Foundation.LayoutService" resolve="true"
							 patch:instead="*[@type='Sitecore.LayoutService.Presentation.Pipelines.RenderJsonRendering.Initialize, Sitecore.LayoutService']"/>
			  </renderJsonRendering>
		  </pipelines>
      </group>
    </pipelines>
  </sitecore>
</configuration>

In the Featured Blogs example above, the Category Droplink field is now rendered with the data from the target item:

Which is a lot more useful than an item ID 🙂

The code for this post is available in my Github repository along with code for the previous posts on the Layout Service.

NOTE: the above code and patch file will be slightly different between Sitecore 9.x Headless Services and Sitecore 10.