I would like to convert the following JSON. As you can see, the array has a single entry. I would like to convert it into a simple string.
{
"@timestamp": [
"2022-05-24T01:53:32.600Z"
],
"site.siteCode": [
"ZAR"
],
"username": [
"QR02159T1"
]
}
I tried to create a JsonConverter
with System.Text.Json but it never call despite adding in the converter.
My Converter:
public class ArrayToSingleConverter : JsonConverter<string>
{
public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.StartArray)
{
// Proper array, we can deserialize from this token onwards.
// return JsonSerializer.Deserialize<List<string>>(ref reader, options);
}
throw new NotImplementedException();
}
public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
{
throw new NotImplementedException();
}
}
The model:
public class Ad4p
{
[JsonPropertyName("site.siteCode")]
[JsonConverter(typeof(ArrayToSingleConverter))]
public string Sitecode { get; set; }
[JsonPropertyName("username")]
[JsonConverter(typeof(ArrayToSingleConverter))]
public string Username { get; set; }
[JsonPropertyName("@timestamp")]
[JsonConverter(typeof(ArrayToSingleConverter))]
public string Timestamp { get; set; }
}
The implementation:
_jsonOptions.Converters.Add(new ArrayOrObjectJsonConverter<string>());
var ad4pList = JsonSerializer.Deserialize<Ad4p>(json, _jsonOptions);
But I have the following error:
Exception thrown: 'System.InvalidOperationException' in System.Text.Json.dll: 'The converter specified on 'CrawlerPowerBi.Models.Ad4p.Sitecode' is not compatible with the type 'System.String'.'
How to convert an array of strings or objects into a single string or object? Thanks.
After some attempts and referring to a similar example Support round trip for Stack,
JsonSerializerOptions _jsonOptions = new JsonSerializerOptions();
var ad4pList = JsonSerializer.Deserialize<Ad4p>(json, _jsonOptions);
public class ArrayToSingleConverter : JsonConverter<string>
{
public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartArray)
{
throw new JsonException();
}
List<string> list = new List<string>();
reader.Read();
while (reader.TokenType != JsonTokenType.EndArray)
{
list.Add(JsonSerializer.Deserialize<string>(ref reader, options));
reader.Read();
}
return list.FirstOrDefault();
}
public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
{
throw new NotImplementedException();
}
}
Supported generic
public class ArrayToSingleConverter<T> : JsonConverter<T>
{
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartArray)
{
throw new JsonException();
}
List<T> list = new List<T>();
reader.Read();
while (reader.TokenType != JsonTokenType.EndArray)
{
list.Add(JsonSerializer.Deserialize<T>(ref reader, options));
reader.Read();
}
return list.FirstOrDefault();
}
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
{
throw new NotImplementedException();
}
}
public class Ad4p
{
[JsonPropertyName("site.siteCode")]
[JsonConverter(typeof(ArrayToSingleConverter<string>))]
public string Sitecode { get; set; }
[JsonPropertyName("username")]
[JsonConverter(typeof(ArrayToSingleConverter<string>))]
public string Username { get; set; }
[JsonPropertyName("@timestamp")]
[JsonConverter(typeof(ArrayToSingleConverter<string>))]
public string Timestamp { get; set; }
}
Alternative:
reader.Read();
while (reader.TokenType != JsonTokenType.EndArray)
{
list.Add(JsonSerializer.Deserialize<T>(ref reader, options));
reader.Read();
}
can be replaced with:
while (reader.Read() && reader.TokenType != JsonTokenType.EndArray)
{
list.Add(JsonSerializer.Deserialize<T>(ref reader, options));
}
As both aimed to read the JSON value until EndArray
was found.