London Dev Meetup Rescheduled! Due to unavoidable reasons, the event has been moved to 21st May. Speakers remain the same—any changes will be communicated. Seats are limited—register here to secure your spot!

Populating IList programmatically causes JsonReaderException

Vote:
0

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:
0

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:
0

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.