Closed antonysmith-mando closed 1 year ago
I think one of the issues here is that the underlying LinkDataCollection
isn't based on JSON at all. It's based on XML and without the proper converters native serialization will fail.
The Content Management API is dependent on the Content Delivery API. Follow the configuration guide here.
This should leave you with an output akin to this:
"thumbnailLinks": [
{
"thumbnail": "62",
"text": "Text",
"title": null,
"target": "_blank",
"href": "/en/alloy-track/",
"attributes": {
"thumbnail": "62",
"href": "/en/alloy-track/",
"target": "_blank"
}
},
...
]
I've had similar issues, so have spent some time trying to make it work for my case (everything below is specific for Content Management API - as Content Delivery API seems to work OK).
Sorry I don't have a solution in the form of pull request, as it might require some rethinking of how to use generic approach to work with Content Management API.
Based on docs here https://docs.developers.optimizely.com/content-cloud/v1.6.0-content-management-api/docs/deserialization
Things I see so far:
1 - Content Management API won't use generic properties (some digging with dotpeek led to this).
So if we have say CustomLinkData
, LinkDataCollection<CustomLinkData>
, and a PropertyCustomLinkDataCollection
for it - we will need a separate model like this CustomLinkDataCollectionPropertyModel : PropertyModel<LinkDataCollection<CustomLinkData>, PropertyCustomLinkDataCollection>
- i.e. we cannot inherit from GenericLinkCollectionPropertyModel<T>
.
2 - This Model should have parameterless constructor, to support JSON deserialization.
3 - And we need yet another converter - this time to implement IPropertyDataValueConverter
.
Here is a minimal sample (in site custom code) I was able to do to make it work with Content Management API and current version of Geta Generic Links:
public class CustomLinkData : LinkData
{
}
[Serializable]
[PropertyDefinitionTypePlugIn]
public class PropertyCustomLinkData : PropertyLinkData<CustomLinkData>
{
}
[Serializable]
[PropertyDefinitionTypePlugIn]
public class PropertyCustomLinkDataCollection : PropertyLinkDataCollection<CustomLinkData>
{
}
public class CustomLinkDataCollectionPropertyModel : PropertyModel<LinkDataCollection<CustomLinkData>, PropertyCustomLinkDataCollection>, IExpandableProperty<LinkDataCollection<CustomLinkData>>
{
// Inner property we're wrapping here
private GenericLinkCollectionPropertyModel<CustomLinkData> InnerProperty { get; }
// We need default constructor to support deserialize from JSON during Content Management API POST requests
[JsonConstructor]
public CustomLinkDataCollectionPropertyModel() : this(new PropertyCustomLinkDataCollection())
{
}
public CustomLinkDataCollectionPropertyModel(PropertyCustomLinkDataCollection type) : base(type)
{
InnerProperty = new GenericLinkCollectionPropertyModel<CustomLinkData>(type, ServiceLocator.Current.GetInstance<IUrlResolver>());
Value = InnerProperty.Value;
}
public virtual LinkDataCollection<CustomLinkData> ExpandedValue
{
get => InnerProperty.ExpandedValue;
set => InnerProperty.ExpandedValue = value;
}
public virtual void Expand(CultureInfo language)
{
InnerProperty.Expand(language);
}
}
[ServiceConfiguration(typeof(IPropertyDataValueConverter))]
[PropertyDataValueConverter(new Type[] { typeof(CustomLinkDataCollectionPropertyModel) })]
internal class CustomLinkDataCollectionPropertyDataValueConverter : IPropertyDataValueConverter
{
public object Convert(IPropertyModel propertyModel, PropertyData propertyData)
{
if (propertyModel is null)
{
throw new ArgumentNullException(nameof(propertyModel));
}
return ((CustomLinkDataCollectionPropertyModel)propertyModel).Value;
}
}
Thanks for the feedback. I'll have a look in the coming days.
I've (finally) concluded that this logic currently has to be implemented on the user side like your example @lanorkin.
The reason for this being how Optimizely implemented registration of IPropertyDataValueConverterResolver
inside an internal namespace. Attaching behaviour to that logic would be brittle and hard to support.
Closing due to inactivity.
Hello,
I'm an Optimizely newbie, so apologies if this is a silly question.
I'm creating items in Optimizely v12 via the Content Management API.
I've got a property of type
LinkDataCollection<GeneralLinkData>
which all works fine in the CMS and via GET requests to the Content Management API.Retrieving a Block with this property contains the following JSON:
However, if I try to create a new Block using exactly the same JSON, I get the following error:
Is there a step I'm missing to allow this object to be deserialised via the Content Management API?
I see there's a separate package for performing conversions for the Content Delivery API (referenced in #6) but not sure if this will solve my problems in the Content Management API and thought I'd ask before throwing myself down a(nother!) rabbit hole.
Any help would be greatly appreciated.
Thanks,
Antony