Question

The Problem

Hi all,

I'm trying to deserialize Json-strings with known (static) and unknown (dynamic) properties. For this I'm using Json.NET and System.Dynamic.DynamicObject. In my first attempt, I was using Json.NET-specific Serialization Attributes to configure the (de-)serializer. However the dynamic properties in the Json-string are not deserialized in that case. But when I switch to native .NET attributes ([DataContract] and [DataMember]), the dynamic properties are deserialized and I can access them in the created dynamic object.

Is this behavior intended? Am I missing any configuration with the Json.NET attributes to get the same deserialization behavior?

Any clarification would be highly appreciated!

The Details

Here I'm providing the details of my implementation (using Json.NET attributes). I'm using .NET 4.5 and Json.NET 6.0.2

Because I have multiple message types with static and dynamic properties, I introduced a base class, which implements the dynamic handling property:

[JsonObject]
internal abstract class DynamicMessage : DynamicObject
{
    [JsonProperty]
    public Dictionary<string, object> dynamicProperties = new Dictionary<string, object();

    public override bool TryGetMember(GetMemberBinder binder, out object result) {...}
    public override bool TrySetMember(SetMemberBinder binder, object value) {...}
}

The concrete subclass is looks like this:

[JsonObject]
internal class ItemMessage : DynamicMessage
{
    [JsonPropertyAttribute(PropertyName = "id")]
    internal long Id;
    [JsonPropertyAttribute(PropertyName = "parent_item");
    internal long ParentItemId;
    ...
}

And I tried the deserialize the following string like this:

jsonString = @{'id':1,
'parent_item':5,
'my_dynamic_property_1' : 1337,
'my_dynamic_property_2' : 'my_dynamic_property_2'}

JsonSerializer serializer  = new JsonSerializer();
dynamic itemMessage = serializer.Deserialize<ItemMessage>(new JsonTextReader(jsonString));

As I pointed out in the beginning, if I'm using the attributes [JsonObject] and [JsonProperty] all static properties are correctly deserialized and bound to the POCO properties, but I'm lacking the dynamic properties my_dynamic_property_1 and my_dynamic_property_2.

When I change to [DataContract] (for [JsonObject]) and [DataMember] (for [JsonProperty]) also the dynamic properties in the Json will be deserialized and I can call

itemMessage.my_dynamic_property_1; //=1337
itemMessage.my_dynamic_property_2; //="my_dynamic_property_2"
Was it helpful?

Solution

[JsonProperty] always binds a single property in the JSON to a single member in a class. You cannot use it to bind multiple JSON properties to a single dictionary. It doesn't work that way.

However, Json.Net does have a [JsonExtensionData] attribute that works the way you want. Try this instead:

[JsonObject]
internal abstract class DynamicMessage : DynamicObject
{
    [JsonExtensionData]
    public Dictionary<string, object> dynamicProperties = 
                                             new Dictionary<string, object>();
    ...
}

OTHER TIPS

This may not be what you're looking for, but you can always deserialize into a dictionary.

var jsonString = @"{'id':1,
'parent_item':5,
'parent_details':{'name': 'parent_name', 'description': 'parent description'},
'array':[1,2,3,4,5,6,7],
'my_dynamic_property_1' : 1337,
'my_dynamic_property_2' : 'my_dynamic_property_2'}";

Dictionary<string, dynamic> values = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(jsonString);

I added a nested object so you can see that it still deserializes into another dictionary with dynamic values to keep everything typed correctly, I also added an array of integers for the same purposes.

You can access your dynamic properties like this:

values[my_dynamic_property_1];

Although I would recommend casting the known types like so:

var prop1 = (int)values["my_dynamic_property_1"];

As for the nested object, you can access the members directly like so:

var parentDescription = values["parent_details"]["name"];
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top