-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JsonSerializer.Deserialize<T> can't work out my array of dictionaries #30856
Comments
I tried this but got a null ref: public class DynamoQueryResult
{
public int Count { get; set; }
public Dictionary<string, JsonElement>[] Items { get; set; }
} |
Yeah I get a null ref from there. The generic argument is irrelevant, I just forgot to cut it from my previous issue which was about it being impossible(?) to deserialize into an IEnumerable of my own design. To widen the view: DynamoValue has several fields: S, N, BOOL, SS, NS, B, BS which are for holding data of different types. The example JSON just shows String fields. If the field contains a String, it goes into the S field. If it's a Number, it goes into the N field. If it's a Number Set (array), it goes into the NS field, and so forth. Yeah, I would probably have had a Type and a Value field, but that's not what the DynamoDB developers decided. Once I have all these multi-typed objects, keyed by their names, I then 'collapse' the Dictionary<string, DynamoValue> into a POCO where the name is the POCO's field, and the value is inferred from a combination of the DynamoValue and the POCO field's type. |
Ultimately my workaround has been to get the data as a JsonElement and then write my own stuff to shuffle the JSON into whatever type I've passed. I also added an implicit operator, so I can just assign a JsonElement to a DynamoQueryResult which is once again IEnumerable |
When deserializing, we explicitly avoid having the payload define the type to deserialize as (in this case, the DynamoValue is a union of several types and the payload tells you which type it should be returned as), which is why capturing the data as JsonElement and handling it explicitly should work. Your workaround makes sense to me. Out of curiosity, @HughPH, what does your
public class DynamoQueryResult<T> where T : class, new()
{
public int Count;
public Dictionary<string, DynamoValue>[] Items;
} Fields are not supported in the current version of the JSON deserializer, which is why neither Count nor Items is being set here (and hence the
Yep, that's a bug in how we are handling array of dictionaries. [Fact]
public static void DeserializeToDictionaryArrayDynamo()
{
string jsonStr =
@"{
""ConsumedCapacity"": {
""CapacityUnits"": 1,
""TableName"": ""Reply""
},
""Count"": 2,
""Items"": [
{
""ReplyDateTime"": { ""S"": ""2015-02-18T20:27:36.165Z""},
""PostedBy"": { ""S"": ""User A""},
""Id"": { ""S"": ""Amazon DynamoDB#DynamoDB Thread 1""}
},
{
""ReplyDateTime"": {""S"": ""2015-02-25T20:27:36.165Z""},
""PostedBy"": { ""S"": ""User B""},
""Id"": { ""S"": ""Amazon DynamoDB#DynamoDB Thread 1""}
}
],
""ScannedCount"": 2
}";
DynamoQueryResult result = JsonSerializer.Deserialize<DynamoQueryResult>(jsonStr);
Assert.Equal(2, result.Count);
Assert.Equal(2, result.Items.Length);
}
public class DynamoQueryResult
{
public int Count { get; set; }
public Dictionary<string, DynamoValue>[] Items { get; set; }
}
public class DynamoValue
{
public string S { get; set; }
public int N { get; set; }
public int[] NS { get; set; }
public bool BOOL { get; set; }
}
This occurs whenever we have an array of [Fact]
public static void DeserializeToDictionaryArray()
{
string jsonStr =
@"{
""Items"": [
{
""property1"": {""Nested"": ""value1""}
},
{
""property2"": {""Nested"": ""value2""}
}
]
}";
DictionaryArray result = JsonSerializer.Deserialize<DictionaryArray>(jsonStr);
Assert.Equal(2, result.Items.Length);
}
public class DictionaryArray
{
public Dictionary<string, NestedType>[] Items { get; set; }
}
public class NestedType
{
public string Nested { get; set; }
}
In the following code, the Set cc @steveharter, @layomia
Here's an issue for |
Thanks Ahson! My code is behind the edit in my previous reply. The real thing has been cleaned up a little, but I still need to address sets (e.g. BS, SS, NS) Cheers |
Here's a similar issue from https://github.com/dotnet/corefx/issues/41198 by @mmosca
|
I can no longer repro the issue with (de)serializing an array of dictionaries. This is likely due to various bug fixes and refactoring efforts we have made since 3.x. Field support to satisfy the initial concern is being tracked here: #876 [Fact]
public static void DeserializeToDictionaryArrayDynamo()
{
string jsonStr =
@"{
""ConsumedCapacity"": {
""CapacityUnits"": 1,
""TableName"": ""Reply""
},
""Count"": 2,
""Items"": [
{
""ReplyDateTime"": { ""S"": ""2015-02-18T20:27:36.165Z""},
""PostedBy"": { ""S"": ""User A""},
""Id"": { ""S"": ""Amazon DynamoDB#DynamoDB Thread 1""}
},
{
""ReplyDateTime"": {""S"": ""2015-02-25T20:27:36.165Z""},
""PostedBy"": { ""S"": ""User B""},
""Id"": { ""S"": ""Amazon DynamoDB#DynamoDB Thread 1""}
}
],
""ScannedCount"": 2
}";
DynamoQueryResult result = JsonSerializer.Deserialize<DynamoQueryResult>(jsonStr);
Assert.Equal(2, result.Count);
Assert.Equal(2, result.Items.Length);
string json = JsonSerializer.Serialize(result, new JsonSerializerOptions { WriteIndented = true });
Console.WriteLine(json);
}
public class DynamoQueryResult
{
public int Count { get; set; }
public Dictionary<string, DynamoValue>[] Items { get; set; }
}
public class DynamoValue
{
public string S { get; set; }
public int N { get; set; }
public int[] NS { get; set; }
public bool BOOL { get; set; }
}
/*
The output is
{
"Count": 2,
"Items": [
{
"ReplyDateTime": {
"S": "2015-02-18T20:27:36.165Z",
"N": 0,
"NS": null,
"BOOL": false
},
"PostedBy": {
"S": "User A",
"N": 0,
"NS": null,
"BOOL": false
},
"Id": {
"S": "Amazon DynamoDB#DynamoDB Thread 1",
"N": 0,
"NS": null,
"BOOL": false
}
},
{
"ReplyDateTime": {
"S": "2015-02-25T20:27:36.165Z",
"N": 0,
"NS": null,
"BOOL": false
},
"PostedBy": {
"S": "User B",
"N": 0,
"NS": null,
"BOOL": false
},
"Id": {
"S": "Amazon DynamoDB#DynamoDB Thread 1",
"N": 0,
"NS": null,
"BOOL": false
}
}
]
}
*/ |
My class is designed to get the items from an Amazon DynamoDB query so that they can be converted to T with a class that implements IEnumerable
Newtonsoft can deserialize into this class with no difficulty at all, but JsonSerializer.Deserialize just leaves the array null.
Example json:
Don't blame me for the insane JSON, blame Amazon. This example is lifted directly out of their DynamoDB documentation (and therefore forms part of my unit tests)
Changing from
Dictionary<string, DynamoValue>[]
toExpandoObject[]
also didn't help, and now I feel dirty.The text was updated successfully, but these errors were encountered: