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

KennyG
May 27, 2025
  857
(1 votes)

Fixing a Sneaky JSON Casing Bug when Exporting in Optimizely CMS

*Note: This issue seems to be resolved with EPiServer.CMS Version 12.33.1.

We recently encountered a pretty frustrating issue while working with Optimizely CMS: after attempting to upgrade to the latest NuGet packages, data exports would just hang—no error, no download, just… spinning forever.

We contacted support, and they had us rule out a timeout problem by tweaking timeout settings in appsettings.json. No luck.
Eventually, after providing Optimizely Support access to a lower environment, they discovered something weird in the export polling response: the JSON was being returned in PascalCase instead of camelCase. Here’s what the problematic JSON looked like:

{
  "FileId": "tmpOMsqJV.tmp",
  "IsDone": true,
  "IsAborting": false,
  "IsTest": false,
  "ErrorMessages": [],
  "WarningMessages": [],
  "InfoMessages": ["Export completed without errors or warnings"],
  "PageCount": 44,
  ...
}

The client-side JavaScript was expecting camelCase (isDone, not IsDone), so even though the export finished, the UI didn’t recognize it. The result? An endless spinner.
After some digging, we found this in our Startup.cs:

services.AddControllers(
    options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true)
    .AddJsonOptions(opts => opts.JsonSerializerOptions.PropertyNamingPolicy = null);

Setting PropertyNamingPolicy to null meant the JSON output kept the C# property casing (PascalCase). Changing that to use JsonNamingPolicy.CamelCase solved the problem:

services.AddControllers(
    options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true)
    .AddJsonOptions(opts => opts.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase);

Once that was in place, the export started working correctly. Of course, we're planning more testing to make sure this doesn't cause side effects elsewhere, but if you run into mysterious export issues after a NuGet update or configuration change—double-check your JSON naming settings. It might just save you hours of Googling.

May 27, 2025

Comments

Mark Stott
Mark Stott May 28, 2025 11:47 AM

Hello Kenny,

Thank you for sharing.  I've encountered this issue as an Add-On owner with CMS Implementations having non-standard serialization conventions at a website level and I've had to collaborate with those CMS Developers to resolve issues like this.  I would suggest not changing the default serialization at a website level, but at a controller method level so that you do not impact the Optimizely functionality or third party Add-On code.  I resolved this in Stott.Optimizely.RobotsHandler and Stott.Security.Optimizely by adding my own convention defining methods within my base controllers so that I don't have to worry about the global configuration:

public class BaseController : Controller
{
    protected static IActionResult CreateSuccessJson<T>(T objectToSerialize)
    {
        return CreateActionResult(HttpStatusCode.OK, objectToSerialize);
    }

    protected static IActionResult CreateValidationErrorJson(ValidationModel validationModel)
    {
        return CreateActionResult(HttpStatusCode.BadRequest, validationModel);
    }

    private static IActionResult CreateActionResult<T>(HttpStatusCode statusCode, T objectToSerialize)
    {
        var serializationOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web)
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        };

        var content = JsonSerializer.Serialize(objectToSerialize, serializationOptions);

        return new ContentResult
        {
            StatusCode = (int)statusCode,
            ContentType = "application/json",
            Content = content
        };
    }
}

Regards,
Mark

KennyG
KennyG Jun 2, 2025 01:21 PM

Mark, I took your advice and went a little more targeted with the fix. https://world.optimizely.com/blogs/kennyg/dates/2025/5/a-targeted-fix-for-json-casing-on-exportdatagetexportstatus-in-optimizely-cms/ Turns out the initial approach broke a couple of React Google Map apps we have on our site so this was needed.

Please login to comment.
Latest blogs
CMS Audiences - check all usage

Sometimes you want to check if an Audience from your CMS (former Visitor Group) has been used by which page(and which version of that page) Then yo...

Tuan Anh Hoang | Dec 12, 2025

Data Imports in Optimizely: Part 2 - Query data efficiently

One of the more time consuming parts of an import is looking up data to update. Naively, it is possible to use the PageCriteriaQueryService to quer...

Matt FitzGerald-Chamberlain | Dec 11, 2025 |

Beginner's Guide for Optimizely Backend Developers

Developing with Optimizely (formerly Episerver) requires more than just technical know‑how. It’s about respecting the editor’s perspective, ensurin...

MilosR | Dec 10, 2025

Optimizely PaaS Administrator Certification : Free for Everyone

Optimizely has recently launched a free PaaS Administrator Certification. https://academy.optimizely.com/student/activity/2958208-paas-cms-administ...

Madhu | Dec 9, 2025 |