Messages | DynamicObject serialization fails
Closed this issue · 3 comments
After changing the serializer for MessagesClient from Newtonsoft.Json
to System.Text.Json
, request serialization is failing under specific circumstances.
As shown below, a request with dynamic content (<dynamic[]>
) ends up partially serialized by the client. It happens because the components
property is a deserialized dynamic object from Newtonsoft.Json
. The following request produces a JObject
, while the serializer expects a JsonElement
.
The real problem is loose typing with a dynamic object, as I assume it would work with strongly typed objects.
Request:
new WhatsAppCustomRequest
{
From = "XXXXX",
To = "XXXXX",
Custom = new
{
type = "template",
template = new
{
@namespace = "c106bb35_2a66_4432_9d19_bffa061064ec",
name = "test_name",
language = new
{
code = "he",
policy = "deterministic",
},
components = JsonConvert.DeserializeObject<dynamic[]>(
"[{\"type\": \"body\",\"parameters\":[{\"type\":\"text\",\"text\":\"hello\"},{\"type\":\"text\",\"text\":\"world\"}]},{\"type\": \"button\",\"index\": \"0\",\"sub_type\": \"url\",\"parameters\": [{\"type\": \"text\",\"text\": \"123456789\"}]}]"),
},
},
}
Serialized:
{
"channel": "whatsapp",
"message_type": "custom",
"to": "XXXXX",
"from": "+XXXXX",
"custom": {
"type": "template",
"template": {
"namespace": "c106bb35_2a66_4432_9d19_bffa061064ec",
"name": "test_name",
"language": {
"code": "he",
"policy": "deterministic"
},
"components": [
{
"type": [],
"parameters": [
[
[
[]
],
[
[]
]
],
[
[
[]
],
[
[]
]
]
]
},
{
"type": [],
"index": [],
"sub_type": [],
"parameters": [
[
[
[]
],
[
[]
]
]
]
}
]
}
}
}
One possible solution could be to rollback to Newtonsoft.Json
.
EDIT: Updated after ongoing investigation
if you are using System.Text.Json then this seems to work:
var components = JsonSerializer.Deserialize<dynamic[]>(
"[{\"type\": \"body\",\"parameters\":[{\"type\":\"text\",\"text\":\"hello\"},{\"type\":\"text\",\"text\":\"world\"}]},{\"type\": \"button\",\"index\": \"0\",\"sub_type\": \"url\",\"parameters\": [{\"type\": \"text\",\"text\": \"123456789\"}]}]");
string json = JsonSerializer.Serialize(components);
Hi @epicqed,
Indeed. After more investigation, the problem comes from using two different serializers: newtonsoft
on the request creation and System.Text.Json
on the request serialization. The following issue is that dynamic values are not populated using the same objects.
I don't recommend using dynamic types in general, but I don't have any control over what's getting in the SDK. As such, moving to System.Text.Json
for Messages is considered a breaking change.
As we talked about internally, this issue won't be fixed.
The library we use for serializing requests is an implementation detail and is, therefore, hidden from users. As such, we can upgrade/switch our dependency as we see fit.
We do not recommend providing serializer-specific items in an object
property (like JObject
or JsonElement
) because it may produce issues.
In the above we situation (TL;DR: provide a deserialized JSON string as dynamic[]
, producing items of type JObject
that our serializer doesn't recognize), there are a few options:
- [recommended] Avoid
dynamic
and favour a concrete object instead. For example, record types are quite handy and could be a one-liner in your codebase. - Avoid using the SDK for this particular call to keep control over the request serialization.
In the future, we'll keep this scenario in mind. When accepting unstructured objects, offering the possibility to provide JSON could be interesting. There's obviously a downside, given we would have to provide two options, and most users won't use Jsonified string.