I have JSON in a response structured like this
{
"statusCode": 200,
"result": {
"generalInfo": {
"firstName": "",
"lastName": ""
},
"isError": false
},
"sentDate": "2022-02-06T10:04:06.6853775Z",
}
var response = await _httpClient.PostAsJsonAsync(address, model);
Stream responseBody = await response.Content.ReadAsStreamAsync();
The response from the endpoint is actually a bit more complex and I want to extract only specific fields so I used dynamic
dynamic data = await JsonSerializer.DeserializeAsync<dynamic>(responseBody)
var dataString = data.ToString();
// dataString is
{"result":{"generalInfo":{"firstName":"John","lastName":"Doe"},"isError":false}
If I try to access dynamic properties like this
var firstName = data.result.generalInfo.firstName;
var lastName = data.result.generalInfo.lastName;
var isErr = data.IsError;
I'm getting exception
'System.Text.Json.JsonElement' does not contain a definition for 'result'
CodePudding user response:
The problem is not DeserializeAsync, but that System.Text.Json uses JsonElements, so the dynamic value is actually a JsonElement. You'll need to parse the data from the JsonElement.
However, if you're using .Net 6 you can use JsonNode:
// deserialize into JsonNode
JsonNode data = await JsonSerializer.DeserializeAsync<JsonNode>(responseBody);
// OR parse the json string
JsonNode data = JsonNode.Parse(dataString);
int statusCode = (int)data["statusCode"];
var firstName = (string)data["result"]["generalInfo"]["firstName"];
var lastName = (string)data["result"]["generalInfo"]["lastName"];
var isErr = (bool)data["result"]["isError"];
Support for dynamic was added to .Net 6 preview v4-6 but was removed before final release in favour of the JsonNode approach above. See github What's new in .NET 6 Preview 7 for further details.
Otherwise, you could parse it manually:
bool isError = false;
string firstName = "";
string lastName = "";
if (data is JsonElement elt && elt.TryGetProperty("result", out elt))
{
isError = elt.TryGetProperty("isError", out JsonElement boolElt) ? boolElt.GetBoolean() : false;
if (elt.TryGetProperty("generalInfo", out var genInfo))
{
firstName = genInfo.TryGetProperty("firstName", out var firstElt) ? firstElt.GetString() : "";
lastName = genInfo.TryGetProperty("lastName", out var lastElt) ? lastElt.GetString() : "";
}
}
However, my preferred approach is always to deserialize into defined classes if you can as it makes life much easier:
public class GeneralInfo
{
public string firstName { get; set; }
public string lastName { get; set; }
}
public class Result
{
public GeneralInfo generalInfo { get; set; }
public bool isError { get; set; }
}
public class Root
{
public Result result { get; set; }
}
var data = await JsonSerializer.DeserializeAsync<Root>(responseBody);
var firstName = data.result.generalInfo.firstName;
