A critical vulnerability was discovered in React Server Components (Next.js). Our systems remain protected but we advise to update packages to newest version. Learn More

Minesh Shah (Netcel)
Feb 15, 2022
  3815
(7 votes)

Property Lists Serialization and Content Delivery API

When utilising property lists in CMS v12 we found the content was not automatically being serialised and returned in the JSON Payload of the Content Delivery API v3.0

To overcome this, we implemented the IPropertyConverter interface found in the EPiServer.ContentApi.Core.Serialization namespace and registered using dependency injection.

Please be aware the Interface’s documentation does state it is currently in Preview State and could introduce breaking changes between minor versions.

To demonstrate the serialization of a property list I have used a simple example of a property list containing of a model containing two string properties.

Example Code:

Create a Property Model Inheriting EPiServer.ContentApi.Core.Serialization.Models.PropertyModel

    public class BenefitItemPropertyModel : PropertyModel<IEnumerable<BenefitItemModel>, PropertyList<BenefitItemModel>>
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="BenefitItemPropertyModel"/> class.
        /// </summary>
        /// <param name="type"></param>
        public BenefitItemPropertyModel(PropertyList<BenefitItemModel> type)
            : base(type)
        {
            Value = GetValues(type.List);
        }

        private IEnumerable<BenefitItemModel> GetValues(IList<BenefitItemModel> items)
        {
            return items.Select(x => new BenefitItemModel
            {
                BenefitText = x.BenefitText,
                BenefitIcon = x.BenefitIcon
            });
        }
    }

Implement the IPropertyConverter Interface and the Convert Method

    public class BenefitItemListPropertyConvertor : IPropertyConverter
    {
        /// <inheritdoc />
        public IPropertyModel Convert(PropertyData propertyData, ConverterContext contentMappingContext)
        {
            return new BenefitItemPropertyModel((PropertyList<BenefitItemModel>)propertyData);
        }
    }

Create a Property Conversion for Property Lists 

    public class ListPropertyConvertorProvider : IPropertyConverterProvider
    {
        private readonly IServiceProvider _serviceProvider;

        /// <summary>
        /// Initializes a new instance of the <see cref="ListPropertyConvertorProvider"/> class.
        /// List property convertor provider
        /// </summary>
        /// <param name="serviceProvider"></param>
        public ListPropertyConvertorProvider(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }

        /// <summary>
        /// The provider which has higher order will be called first to see if it handles specified <see cref="PropertyData" /> type
        /// </summary>
        public int SortOrder => 1000;

        /// <summary>
        /// Determines if provider supports specified <paramref name="propertyData" /> type and if so returns a matching
        /// <see cref="IPropertyConverter" /> instance. If <paramref name="propertyData" /> is not supported return null
        /// </summary>
        /// <param name="propertyData">instance of <see /> to resolve <see /> for</param>
        /// <returns>A matching <see /> or null if <paramref name="propertyData" /> is not supported by the provider</returns>
        public IPropertyConverter Resolve(PropertyData propertyData)
        {
            return propertyData switch
            {
                PropertyList<BenefitItemModel> => _serviceProvider.GetService<BenefitItemListPropertyConvertor>(),
                _ => null,
            };
        }
    }

Register the dependency in the Startup.cs Class

services.TryAddEnumerable(ServiceDescriptor.Singleton<IPropertyConverterProvider, ListPropertyConvertorProvider>());
services.TryAddScoped<BenefitItemListPropertyConvertor>();

Having implemented the above you should get the following response from the content delivery API

                "displayOption": "col-6",
                "contentLink": {
                    "id": 146,
                    "workId": 0,
                    "guidValue": "83db556b-a029-4108-8b38-0cf4a29c9d9a",
                    "expanded": {
                        "contentLink": {
                            "id": 146,
                            "workId": 0,
                            "guidValue": "83db556b-a029-4108-8b38-0cf4a29c9d9a"
                        },
                        "name": " Benefits",
                        "contentType": [
                            "Block",
                            "BenefitsBlock"
                        ],
                        "theme": "green",
                        "benefits": [
                            {
                                "benefitIcon": "icon_pound",
                                "benefitText": "Lorem ipsum dolor sit amet"
                            },
                            {
                                "benefitIcon": "icon_pound",
                                "benefitText": "Lorem ipsum dolor sit amet"
                            }
                        ]
                    }
                }
            },
Feb 15, 2022

Comments

Akasha Nasir
Akasha Nasir Oct 21, 2022 05:22 PM

Hi Manesh,

Thanks for the Posting. I tried the above solution but it seems to be does'nt work for content delivery API 3.0. I am able to post List type data in CMS. But Unable to get List type object via Content delivery API 3.0.

ItemModel :

Property Model:

Converter:

Startup:

Is there anything missed which I need to configure?

Thanks

Minesh Shah (Netcel)
Minesh Shah (Netcel) Oct 21, 2022 08:39 PM

Hi Akasha

I completly forgot about the Property Convertor class (ListPropertyConvertorProvider) for Property Lists, I have now updated the blog post. 

You can also see a working example here : Netcel-Optimizely/Optimizely-ContentDelivery-Examples: An example project built on Content Cloud v12 showcasing how the Content Delivery API can be extended (github.com) 

Output example 

Akasha Nasir
Akasha Nasir Oct 21, 2022 09:44 PM

Hi Manesh,

Thank you for your tremendous help. Now, It is working. You save my night. Your blog is very nice and surely will help others.

Excellent work!

Please login to comment.
Latest blogs
Looking back at Optimizely in 2025

Explore Optimizely's architectural shift in 2025, which removed coordination cost through a unified execution loop. Learn how agentic Opal AI and...

Andy Blyth | Dec 17, 2025 |

Cleaning Up Content Graph Webhooks in PaaS CMS: Scheduled Job

The Problem Bit of a niche issue, but we are building a headless solution where the presentation layer is hosted on Netlify, when in a regular...

Minesh Shah (Netcel) | Dec 17, 2025

A day in the life of an Optimizely OMVP - OptiGraphExtensions v2.0: Enhanced Search Control with Language Support and Synonym Slots

Supercharge your Optimizely Graph search experience with powerful new features for multilingual sites and fine-grained search tuning. As search...

Graham Carr | Dec 16, 2025

A day in the life of an Optimizely OMVP - Optimizely Opal: Specialized Agents, Workflows, and Tools Explained

The AI landscape in digital experience platforms has shifted dramatically. At Opticon 2025, Optimizely unveiled the next evolution of Optimizely Op...

Graham Carr | Dec 16, 2025

Optimizely CMS - Learning by Doing: EP09 - Create Hero, Breadcrumb's and Integrate SEO : Demo

  Episode 9  is Live!! The latest installment of my  Learning by Doing: Build Series  on  Optimizely Episode 9 CMS 12  is now available on YouTube!...

Ratish | Dec 15, 2025 |

Building simple Opal tools for product search and content creation

Optimizely Opal tools make it easy for AI agents to call your APIs – in this post we’ll build a small ASP.NET host that exposes two of them: one fo...

Pär Wissmark | Dec 13, 2025 |