November Happy Hour will be moved to Thursday December 5th.

Populating IList programmatically causes JsonReaderException

Vote:
 

We create and populate catalogs from a PIM system, and I've suggested that we use IList<string> for a property to ease the experience for the editors.

However, when we (try to) populate this IList via code, it casts an JsonReaderException if the PIM property-equivalent has values.

This is how the PIM property looks like per language:

<LocaleString>
<Language>no</Language>
<Value>Value 1 test
Value 2 test</Value>
</LocaleString>

The values are splitted by \r\n, meaning the above results in a dictionary with the language value ("no"), and a list of strings ("Value 1 test", "Value 2 test").

This is the code I'm using to split:

private Dictionary<string, List<string>> GetBulletPoints(Dictionary<string, string> productBulletsString)
{
var bulletPoints = new Dictionary<string, List<string>>();
var stringSeparators = new[] { "\r\n" };
foreach (var bulletPoint in productBulletsString)
{
bulletPoints.Add(bulletPoint.Key, bulletPoint.Value.Split(stringSeparators, StringSplitOptions.RemoveEmptyEntries).ToList());
}

}

and this is what I use to get the list of strings depending on the culture info:

private bool TryGetStringList(Dictionary<string, List<string>> localeString, out List<string> stringValue, string language)
{
stringValue = new List<string>();
if (localeString == null || !localeString.Any()) return false;

var mappedLanguage = _languageMapperRepository.Get(language);
return localeString.TryGetValue(mappedLanguage, out stringValue);
}

The IList-property looks like this:

[Display(
Order = 190)]
[Editable(true)]
[CultureSpecific]
[BackingType(typeof(PropertyStringList))]
public virtual IList<string> UniqueSellingPoints{ get; set;}

UniqueSellingPoints is then assigned to the list of string.

However, this results in the following error message:

[JsonReaderException: Unexpected character encountered while parsing value: T. Path '', line 0, position 0.]
   Newtonsoft.Json.JsonTextReader.ParseValue() +1295
   Newtonsoft.Json.JsonReader.ReadForType(JsonContract contract, Boolean hasConverter) +99
   Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent) +796
   Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType) +279
   EPiServer.Framework.Serialization.Json.Internal.JsonObjectSerializer.Deserialize(TextReader reader, Type objectType) +71
   EPiServer.Framework.Serialization.ObjectSerializerExtensions.Deserialize(IObjectSerializer serializer, String value, Type objectType) +109
   EPiServer.Commerce.Catalog.Provider.MetaDataPropertyMapper.AssignMetaFieldValueToProperty(PropertyData property, Object metaFieldValue, MetaDataType metaDataType, String blockPropertyMetaFieldName) +881
   EPiServer.Commerce.Catalog.Provider.Construction.CatalogPropertyLoader.AddMetaDataAttributePropertyValues(MetaObjectAccessor accessor, CatalogContentBase content) +1364
   EPiServer.Commerce.Catalog.Provider.Construction.CatalogPropertyLoader.LoadProperties(CatalogEntryRow entryRow, CatalogItemSeoRow seoRow, VariationRow variationRow, EntryContentBase content, MetaObjectAccessor metaObjectAccessor) +246
   EPiServer.Commerce.Catalog.Provider.Construction.EntryBuilder.ConstructEntries(CatalogEntryDto entryDto, IDictionary`2 versionsForUnpublishedContent, IList`1 entryNodeRelations, String language) +1569
   EPiServer.Commerce.Catalog.Provider.Construction.EntryBuilder.Create(IList`1 contentLinks, String language) +877
   EPiServer.Commerce.Catalog.Provider.CatalogContentLoader.ConstructContent(IList`1 contentLinks, Func`3 createContentFunc) +512
   EPiServer.Commerce.Catalog.Provider.CatalogContentLoader.LoadSpecificContentInstances(IList`1 contentLinks, String language) +608
   EPiServer.Commerce.Catalog.Provider.CatalogContentProvider.BatchLoad(IList`1 contentLinks, Func`2 dbLoader) +247
   EPiServer.Commerce.Catalog.Provider.CatalogContentProvider.LoadContents(IList`1 contentReferences, ILanguageSelector selector) +753
   EPiServer.Commerce.Catalog.Provider.CatalogContentProvider.LoadContent(ContentReference contentLink, ILanguageSelector languageSelector) +198
   EPiServer.Core.<>c__DisplayClass121_0.<LoadContentFromCacheOrRepository>b__0() +35
   EPiServer.Framework.Cache.ObjectInstanceCacheExtensions.ReadThroughWithWait(IObjectInstanceCache cache, String cacheKey, Func`1 readValue, Func`2 evictionPolicy) +993
   EPiServer.Core.Internal.ContentInstanceCache.ReadThrough(ContentReference contentLink, String selectedLanguage, Func`1 readValue) +107
   EPiServer.Core.ContentProvider.LoadContentFromCacheOrRepository(ContentReference contentreference, ILanguageSelector selector) +617
   EPiServer.Core.Internal.DefaultContentLoader.GetBySegmentInternal(ContentProvider provider, ContentReference parentLink, String urlSegment, LoaderOptions loaderOptions) +538
   EPiServer.Core.Internal.DefaultContentLoader.GetBySegment(ContentReference parentLink, String urlSegment, LoaderOptions selector) +93
   EPiServer.Commerce.Routing.HierarchicalCatalogPartialRouter.FindNextContentInSegmentPair(CatalogContentBase catalogContent, SegmentPair segmentPair, SegmentContext segmentContext, CultureInfo cultureInfo) +478
   EPiServer.Commerce.Routing.HierarchicalCatalogPartialRouter.GetCatalogContentRecursive(CatalogContentBase catalogContent, SegmentPair segmentPair, SegmentContext segmentContext, CultureInfo cultureInfo) +200
   EPiServer.Commerce.Routing.HierarchicalCatalogPartialRouter.RoutePartial(PageData content, SegmentContext segmentContext) +347
   EPiServer.Web.Routing.Segments.Internal.PartialSegment.RouteDataMatch(SegmentContext context) +358
   System.Linq.Enumerable.All(IEnumerable`1 source, Func`2 predicate) +170
   EPiServer.Web.Routing.Internal.DefaultContentRoute.RouteSegmentContext(SegmentContext segmentContext) +16
   EPiServer.Web.Routing.Internal.DefaultContentRoute.GetRouteData(HttpContextBase httpContext) +466
   System.Web.Routing.RouteCollection.GetRouteData(HttpContextBase httpContext) +239
   EPiServer.Web.Routing.RouteCollectionExtensions.HandleRouteData(RouteCollection routes, HttpContextBase context) +30
   EPiServer.Global.DefaultDocumentHandling(Object sender, EventArgs e) +180
   System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +142
   System.Web.<>c__DisplayClass285_0.<ExecuteStepImpl>b__0() +38
   System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step) +11855053
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +93

Does anyone know what causes this? I'm not really familiar with how the IList works - where does the JsonReader come in?

#210814
Dec 06, 2019 15:00
Vote:
 

I don't think IList<string> is supported in the catalog content. You probably need to use ItemCollection<string> instead, something like this

[BackingType(typeof(PropertyDictionaryMultiple))]
[CultureSpecific]
public virtual ItemCollection<string> MultiValueDictionary { get; set; }

#210818
Edited, Dec 06, 2019 16:24
Vote:
 

https://world.episerver.com/forum/developer-forum/-Episerver-75-CMS/Thread-Container/2018/8/trying-to-use-the-contentreferencelist-property-but-getting-exception/

That's odd. In the thread I'm referring to above you say: "Commerce contents have full support for IList<T>". Isn't content that inherits from ProductContent commerce content? If not, how does it differ from catalog content?

Also, from what I can tell, the property you're suggesting unfortunately doesn't fit my need - PropertyDictionaryMultiple is a list of checkboxes, isn't it? What I'm looking for is the ability to add strings in a list, and I've used IList before and thought it would fit this case too. It is rendered if there are no values (added programmatically) - that's why I think there must be something up with the conversion and/or backing type. Image below shows what it looks like if there are added values manually. There's only an issue adding the values programmatically - that what throws the weird JsonReaderException. It is possible to use something other than  [BackingType(typeof(PropertyStringList))] as backing type?

 

#210876
Dec 09, 2019 11:54
Quan Mai - Dec 09, 2019 13:18
Apparently I was wrong - it should be supported. I will look into this when I have more time to spare.
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.