This question applies to custom deserialization classes for System.Text.Json
in .Net Core 3.1.
I'm trying to understand why custom deserialization class needs to read to the end of the JSON stream even though it has already produced the required data, otherwise the deserialization fails with JsonException
that ends with "read too much or not enough."
I read through Microsoft Documentation for System.Text.Json
([1], [2]), but couldn't figure that out.
Here is an example of the document:
{
"Response": {
"Result": [
{
"Code": "CLF",
"Id": 49,
"Type": "H"
},
{
"Code": "CLF",
"Id": 42,
"Type": "C"
}
]
}
}
The DTO class and deserialisation method are defined as following:
public class EntityDto
{
public string Code { get; set; }
public int Id { get; set; }
public string Type { get; set; }
}
// This method is a part of class EntityDtoIEnumerableConverter : JsonConverter<IEnumerable<EntityDto>>
public override IEnumerable<EntityDto> Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException("JSON payload expected to start with StartObject token.");
}
while ((reader.TokenType != JsonTokenType.StartArray) && reader.Read()) { }
var eodPostions = JsonSerializer.Deserialize<EntityDto[]>(ref reader, options);
// This loop is required to not get JsonException
while (reader.Read()) { }
return new List<EntityDto>(eodPostions);
}
Here is how the deserialization class is called.
var serializerOptions = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
serializerOptions.Converters.Add(new EntityDtoIEnumerableConverter());
HttpResponseMessage message = await httpClient.GetAsync(requestUrl);
message.EnsureSuccessStatusCode();
var contentStream = await msg.Content.ReadAsStreamAsync();
var result = await JsonSerializer.DeserializeAsync<IEnumerable<EntityDto>>(contentStream, serializerOptions);
When the last loop while (reader.Read()) { }
in deserialization method is absent, or commented out, the last call await JsonSerializer.DeserializeAsync<...
fails with the JsonException
, which ends with read too much or not enough
. Can anyone explain why? Or is there a better way to write this deserialization?
Updated the second block of code to use EntityDtoIEnumerableConverter
.