It is possible to deserialize an array with Json.NET. How can I deserialize the following JSON using System.Text.Json?
JSON
[340,{"a":["21040.00000",0,"0.00500000"],"b":["21037.70000",0,"0.49900000"],"c":["21039.00000","0.06009660"],"v":["660.49276224","3641.23932460"],"p":["20783.06665","20853.16080"],"t":[6207,22883],"l":["20500.10000","20500.10000"],"h":["21052.40000","21528.70000"],"o":["20716.30000","21416.30000"]},"ticker","XBT/USD"]
Json.NET way
[JsonConverter(typeof(ArrayConverter))]
public class KrakenSocketEvent<T>
{
[ArrayProperty(0)]
public int ChannelId { get; set; }
[ArrayProperty(1)]
[JsonConversion]
public T Data { get; set; } = default!;
[ArrayProperty(2)]
public string Topic { get; set; } = string.Empty;
[ArrayProperty(3)]
public string Symbol { get; set; } = string.Empty;
}
Edit
What I currently have is the following. The issue is with the typeparam. I'm getting a compile time error.
[JsonConverter(typeof(JsonNumberHandlingPlainArrayConverter<KrakenSocketEvent<T>>))] // Attribute argument cannot use type parameters
public record KrakenSocketEvent<T> where T : new()
{
[JsonPlainArrayIndex(0)]
public int ChannelId { get; init; }
[JsonPlainArrayIndex(1)]
public T Data { get; init; } = default!;
[JsonPlainArrayIndex(2)]
public string Topic { get; init; } = null!;
[JsonPlainArrayIndex(3)]
public string Symbol { get; init; } = null!;
}
public sealed class JsonNumberHandlingPlainArrayConverter<T> : JsonPlainArrayConverter<T> where T : new()
{
protected override JsonSerializerOptions CustomizePropertyOptions(PropertyInfo info, JsonSerializerOptions options)
{
return new JsonSerializerOptions(options)
{
NumberHandling = JsonNumberHandling.AllowReadingFromString
};
}
}
[AttributeUsage(AttributeTargets.Property)]
public sealed class JsonPlainArrayIndexAttribute : Attribute
{
public JsonPlainArrayIndexAttribute(int index)
{
Index = index;
}
public int Index { get; }
}
public class JsonPlainArrayConverter<T> : JsonConverter<T> where T : new()
{
protected virtual JsonSerializerOptions CustomizePropertyOptions(PropertyInfo info, JsonSerializerOptions options)
{
return options;
}
public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
Debug.Assert(typeof(T) == typeToConvert);
var props = typeToConvert.GetProperties();
var linq = from prop in props
let attr = prop.GetCustomAttributes(typeof(JsonPlainArrayIndexAttribute), true)
where prop.CanWrite && attr.Length is 1
orderby ((JsonPlainArrayIndexAttribute)attr[0]).Index
select prop;
var arr = JsonSerializer.Deserialize<IEnumerable<JsonElement>>(ref reader, options);
if (arr is null)
{
return default;
}
var result = new T();
foreach (var (prop, value) in linq.Zip(arr))
{
prop.SetValue(result, value.Deserialize(prop.PropertyType, CustomizePropertyOptions(prop, options)));
}
return result;
}
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
{
var type = typeof(T);
var props = type.GetProperties();
var linq = from prop in props
let attr = prop.GetCustomAttributes(typeof(JsonPlainArrayIndexAttribute), true)
where prop.CanRead && attr.Length is 1
orderby ((JsonPlainArrayIndexAttribute)attr[0]).Index
select prop.GetValue(value);
JsonSerializer.Serialize<IEnumerable<object>>(writer, linq, options);
}
}