Url, PageReference serialization issue in CMS 11

  • Updated

We have a couple of cases since upgrading to Epi 11 using the EPiServer.Url or EPiServer.PageReference in a repeatable list caused an exception and no value to be stored. See epi log below:

2018-02-26 14:00:09,403 [1] ERROR EPiServer.DataAccess.Internal.JsonPropertyValueConverter: An exception occurred while converting JSON property 
Newtonsoft.Json.JsonSerializationException: Error getting value from 'QueryCollection' on 'EPiServer.Url'. ---> System.NullReferenceException: Object reference not set to an instance of an object. 
at EPiServer.Web.UriUtil.SplitInternal(String url, Int32 offset) 
at EPiServer.Url.get_Split() 
at EPiServer.Url.get_QueryCollection() 
at GetQueryCollection(Object ) 
at Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target) 
--- End of inner exception stack trace --- 
at Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target) 
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CalculatePropertyDetails(JsonProperty property, JsonConverter& propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target, Boolean& useExistingValue, Object& currentValue, JsonContract& propertyContract, Boolean& gottenCurrentValue) 
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target) 
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id) 
2018-02-26 14:00:09,451 [1] ERROR EPiServer.DataAccess.Internal.JsonPropertyValueConverter: An exception occurred while converting JSON property 
Newtonsoft.Json.JsonSerializationException: Error getting value from 'Segments' on 'EPiServer.Url'. ---> System.ArgumentNullException: Value cannot be null. 
Parameter name: uriString 
at System.Uri..ctor(String uriString, UriKind uriKind) 
at EPiServer.Url.EnsureUri() 
at EPiServer.Url.get_UriInternal() 
at GetSegments(Object ) 
at Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target) 
--- End of inner exception stack trace --- 
at Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target) 
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CalculatePropertyDetails(JsonProperty property, JsonConverter& propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target, Boolean& useExistingValue, Object& currentValue, JsonContract& propertyContract, Boolean& gottenCurrentValue) 
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target) 
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)

The PropertyList was designed primarily to be used with simple types such as int, string, etc and the “out-of-the-box experience” will only cater for such types. If they want to use a more complex type both responsible for making sure that the type can be serialized (using Json.NET) and that it’s properly decorated for editing. 

There were some changes in CMS 11 as listed here.

PropertyList<T> improvements (Beta removal)

  • EPiServer.Core.Transfer.IRawContentRetriever will no longer populate the Value of each RawProperty. This is instead done by calling the IPropertyExporter.ExportProperties method.
  • EPiServer.Core.Transfer.IPropertyImporter has changed slightly to match the new IPropertyExporter interface.
  • PropertyData.ToRawString() will no longer be called when exporting data. If a Custom PropertyData type had previously overridden the ToRawValue method, it must now move that functionality to a class that implements IPropertyExportTransform and register it with the Container.
  • PropertyJson-based properties, such as PropertyList, no longer rely on IObjectSerializer and container registered JsonConverters for its serialization. It now uses Newtonsoft.Json.JsonConvert directly, which means JsonConverters must be defined as attributes on the classes and properties they apply to.


So if they use Url property what they likely need is to decorate for this property as seen below.

        [JsonProperty]
        [JsonConverter(typeof(UrlConverter))]


If they use PageReference property, the way to make it works is to write a JsonConverter just like in the case of the UrlConverter.
It's not hard to build a naive one that just serializes the PageReference to a string and back again but we really need to be clear that this is not a supported way and that we are not responsible for any data loss.