Reputation: 13
Im getting strange results when attempting to desirilize a json object in c#.I have been the same process to deserilze other json objects with no issue but this one just seems to be giving me strange results. the jsonresult in json explorer looks fine, however i have noticed the it places 1,2,3 objects under data I presumed the list would catch this. but im still receiving null for some of the object.
I have the following json object.
{
"data": [
{
"block": {
"id": 0,
"hash": "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f",
"date": "2009-01-03",
"time": "2009-01-03 18:15:05",
"median_time": "2009-01-03 18:15:05",
"size": 285,
"stripped_size": 285,
"weight": 1140,
"version": 1,
"version_hex": "1",
"version_bits": "000000000000000000000000000001",
"merkle_root": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b",
"nonce": 2083236893,
"bits": 486604799,
"difficulty": 1,
"chainwork": "0000000000000000000000000000000000000000000000000000000100010001",
"coinbase_data_hex": "04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73",
"transaction_count": 1,
"witness_count": 0,
"input_count": 1,
"output_count": 1,
"input_total": 0,
"input_total_usd": 0,
"output_total": 5000000000,
"output_total_usd": 0.5,
"fee_total": 0,
"fee_total_usd": 0,
"fee_per_kb": 0,
"fee_per_kb_usd": 0,
"fee_per_kwu": 0,
"fee_per_kwu_usd": 0,
"cdd_total": 0,
"generation": 5000000000,
"generation_usd": 0.5,
"reward": 5000000000,
"reward_usd": 0.5,
"guessed_miner": "Unknown"
},
"transactions": [
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
]
}
],
"context": {
"code": 200,
"source": "D",
"time": 0.43245887756347656,
"limit": 100,
"offset": 0,
"results": 1,
"state": 602572,
"cache": {
"live": true,
"duration": 15,
"since": "2019-11-06 09:45:13",
"until": "2019-11-06 09:45:28",
"time": null
},
"api": {
"version": "2.0.39",
"last_major_update": "2019-07-19 18:07:19",
"next_major_update": null,
"tested_features": "omni-v.a1,whc-v.a1,aggregate-v.b5,xpub-v.b5,ripple-v.a1,ethgraph-v.a1,erc_20-v.a1",
"documentation": "https://github.com/Blockchair/Blockchair.Support/blob/master/API.md",
"notice": "Beginning July 19th, 2019 all applications using Blockchair API on a constant basis should apply for an API key (mailto:[email protected])"
}
}
}
The classes i have created while testing are:
[System.Serializable]
public class BTCBlock
{
public int id { get; set; }
public string hash { get; set; }
public string date { get; set; }
public string time { get; set; }
public string median_time { get; set; }
public int size { get; set; }
public int stripped_size { get; set; }
public int weight { get; set; }
public int version { get; set; }
public string version_hex { get; set; }
public string version_bits { get; set; }
public string merkle_root { get; set; }
public int nonce { get; set; }
public int bits { get; set; }
public int difficulty { get; set; }
public string chainwork { get; set; }
public string coinbase_data_hex { get; set; }
public int transaction_count { get; set; }
public int witness_count { get; set; }
public int input_count { get; set; }
public int output_count { get; set; }
public int input_total { get; set; }
public int input_total_usd { get; set; }
public long output_total { get; set; }
public double output_total_usd { get; set; }
public int fee_total { get; set; }
public int fee_total_usd { get; set; }
public int fee_per_kb { get; set; }
public int fee_per_kb_usd { get; set; }
public int fee_per_kwu { get; set; }
public int fee_per_kwu_usd { get; set; }
public int cdd_total { get; set; }
public long generation { get; set; }
public double generation_usd { get; set; }
public long reward { get; set; }
public double reward_usd { get; set; }
public string guessed_miner { get; set; }
}
[System.Serializable]
public class BTCDatum
{
public BTCBlock block { get; set; }
public List<string> transactions { get; set; }
}
[System.Serializable]
public class BTCCache
{
public bool live { get; set; }
public int duration { get; set; }
public string since { get; set; }
public string until { get; set; }
public object time { get; set; }
}
[System.Serializable]
public class BTCApi
{
public string version { get; set; }
public string last_major_update { get; set; }
public object next_major_update { get; set; }
public string tested_features { get; set; }
public string documentation { get; set; }
public string notice { get; set; }
}
[System.Serializable]
public class BTCContext
{
public int code { get; set; }
public string source { get; set; }
public double time { get; set; }
public int limit { get; set; }
public int offset { get; set; }
public int results { get; set; }
public int state { get; set; }
public BTCCache cache { get; set; }
public BTCApi api { get; set; }
}
[System.Serializable]
public class BTCRootObject
{
public BData data { get; set; }
public BTCContext context { get; set; }
}
[System.Serializable]
public class BData
{
public List<BTCDatum> datrum;
}
When i try to get my result context and BData are fine but the BTCDatum is null! Here is the code used from Json.net library.
string jsonresult = System.Text.Encoding.UTF8.GetString(www.downloadHandler.data);
BTCRootObject BTC_Block = JsonConvert.DeserializeObject<BTCRootObject>(jsonresult);
Here is the json for anthing after 0 blocks: I have no idea how to handle the 1,2 and so on.
{
"data": {
"2": {
"block": {
"id": 2,
"hash": "000000006a625f06636b8bb6ac7b960a8d03705d1ace08b1a19da3fdcc99ddbd",
"date": "2009-01-09",
"time": "2009-01-09 02:55:44",
"median_time": "2009-01-09 02:54:25",
"size": 215,
"stripped_size": 215,
"weight": 860,
"version": 1,
"version_hex": "1",
"version_bits": "000000000000000000000000000001",
"merkle_root": "9b0fc92260312ce44e74ef369f5c66bbb85848f2eddd5a7a1cde251e54ccfdd5",
"nonce": 1639830024,
"bits": 486604799,
"difficulty": 1,
"chainwork": "0000000000000000000000000000000000000000000000000000000300030003",
"coinbase_data_hex": "04ffff001d010b",
"transaction_count": 1,
"witness_count": 0,
"input_count": 1,
"output_count": 1,
"input_total": 0,
"input_total_usd": 0,
"output_total": 5000000000,
"output_total_usd": 0.5,
"fee_total": 0,
"fee_total_usd": 0,
"fee_per_kb": 0,
"fee_per_kb_usd": 0,
"fee_per_kwu": 0,
"fee_per_kwu_usd": 0,
"cdd_total": 0,
"generation": 5000000000,
"generation_usd": 0.5,
"reward": 5000000000,
"reward_usd": 0.5,
"guessed_miner": "Unknown"
},
"transactions": [
"9b0fc92260312ce44e74ef369f5c66bbb85848f2eddd5a7a1cde251e54ccfdd5"
]
},
"1": {
"block": {
"id": 1,
"hash": "00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048",
"date": "2009-01-09",
"time": "2009-01-09 02:54:25",
"median_time": "2009-01-09 02:54:25",
"size": 215,
"stripped_size": 215,
"weight": 860,
"version": 1,
"version_hex": "1",
"version_bits": "000000000000000000000000000001",
"merkle_root": "0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098",
"nonce": 2573394689,
"bits": 486604799,
"difficulty": 1,
"chainwork": "0000000000000000000000000000000000000000000000000000000200020002",
"coinbase_data_hex": "04ffff001d0104",
"transaction_count": 1,
"witness_count": 0,
"input_count": 1,
"output_count": 1,
"input_total": 0,
"input_total_usd": 0,
"output_total": 5000000000,
"output_total_usd": 0.5,
"fee_total": 0,
"fee_total_usd": 0,
"fee_per_kb": 0,
"fee_per_kb_usd": 0,
"fee_per_kwu": 0,
"fee_per_kwu_usd": 0,
"cdd_total": 0,
"generation": 5000000000,
"generation_usd": 0.5,
"reward": 5000000000,
"reward_usd": 0.5,
"guessed_miner": "Unknown"
},
"transactions": [
"0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098"
]
}
},
"context": {
"code": 200,
"source": "D",
"time": 0.4254789352416992,
"limit": 100,
"offset": 0,
"results": 2,
"state": 602730,
"cache": {
"live": true,
"duration": 60,
"since": "2019-11-07 13:50:19",
"until": "2019-11-07 13:51:19",
"time": null
},
"api": {
"version": "2.0.39",
"last_major_update": "2019-07-19 18:07:19",
"next_major_update": null,
"tested_features": "omni-v.a1,whc-v.a1,aggregate-v.b5,xpub-v.b5,ripple-v.a1,ethgraph-v.a1,erc_20-v.a1",
"documentation": "https://github.com/Blockchair/Blockchair.Support/blob/master/API.md",
"notice": "Beginning July 19th, 2019 all applications using Blockchair API on a constant basis should apply for an API key (mailto:[email protected])"
}
}
}
Upvotes: 1
Views: 156
Reputation: 18163
Please refer update section.
Problem 1: Wrong Definition of BTCRootObject
You problem lies with the definition of BTCRootObject. As per OP, the BTCRootObject is defined as
[System.Serializable]
public class BTCRootObject
{
public BData data { get; set; }
public BTCContext context { get; set; }
}
[System.Serializable]
public class BData
{
public List<BTCDatum> datrum;
}
If you examine the JSON, you can observe that root object contains an array of BTCDatum.However, as per the code given in OP, it contains an instance of BData, which inturn contains collection of BTCDatum.
This needs to be corrected as the following
[System.Serializable]
public class BTCRootObject
{
public List<BTCDatum> data { get; set; }
public BTCContext context { get; set; }
}
Update : Based on Edit in OP
Problem 2: Collection and Object for data
The second problem lies with the fact that the data
could be array or object based on the two sample Json you have provided. In order to handle this, you could create a JsonConverter, which converts a Single Object to a collection. For example,
public class SingleValueArrayConverter<T> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(List<T>));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
if (token.Type == JTokenType.Array)
{
return token.ToObject<List<T>>();
}
return new List<T> { token.Children().First().First().ToObject<T>() };
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
List<T> list = (List<T>)value;
if (list.Count == 1)
{
value = list[0];
}
serializer.Serialize(writer, value);
}
public override bool CanWrite
{
get { return true; }
}
}
Now you can change the definition of BTCRootObject as
[System.Serializable]
public class BTCRootObject
{ [JsonConverter(typeof(SingleValueArrayConverter<BTCDatum>))]
public List<BTCDatum> data { get; set; }
public BTCContext context { get; set; }
}
Problem 3: BTCBlock.nonce needs to be long
The BTCBlock.nonce property needs to be long instead of Int as seen in the second example Json you have provided.
Your final data structure would look like following.
[System.Serializable]
public class BTCBlock
{
public int id { get; set; }
public string hash { get; set; }
public string date { get; set; }
public string time { get; set; }
public string median_time { get; set; }
public int size { get; set; }
public int stripped_size { get; set; }
public int weight { get; set; }
public int version { get; set; }
public string version_hex { get; set; }
public string version_bits { get; set; }
public string merkle_root { get; set; }
public long nonce { get; set; }
public int bits { get; set; }
public int difficulty { get; set; }
public string chainwork { get; set; }
public string coinbase_data_hex { get; set; }
public int transaction_count { get; set; }
public int witness_count { get; set; }
public int input_count { get; set; }
public int output_count { get; set; }
public int input_total { get; set; }
public int input_total_usd { get; set; }
public long output_total { get; set; }
public double output_total_usd { get; set; }
public int fee_total { get; set; }
public int fee_total_usd { get; set; }
public int fee_per_kb { get; set; }
public int fee_per_kb_usd { get; set; }
public int fee_per_kwu { get; set; }
public int fee_per_kwu_usd { get; set; }
public int cdd_total { get; set; }
public long generation { get; set; }
public double generation_usd { get; set; }
public long reward { get; set; }
public double reward_usd { get; set; }
public string guessed_miner { get; set; }
}
[System.Serializable]
public class BTCDatum
{
public BTCBlock block { get; set; }
public List<string> transactions { get; set; }
}
[System.Serializable]
public class BTCCache
{
public bool live { get; set; }
public int duration { get; set; }
public string since { get; set; }
public string until { get; set; }
public object time { get; set; }
}
[System.Serializable]
public class BTCApi
{
public string version { get; set; }
public string last_major_update { get; set; }
public object next_major_update { get; set; }
public string tested_features { get; set; }
public string documentation { get; set; }
public string notice { get; set; }
}
[System.Serializable]
public class BTCContext
{
public int code { get; set; }
public string source { get; set; }
public double time { get; set; }
public int limit { get; set; }
public int offset { get; set; }
public int results { get; set; }
public int state { get; set; }
public BTCCache cache { get; set; }
public BTCApi api { get; set; }
}
[System.Serializable]
public class BTCRootObject
{ [JsonConverter(typeof(SingleValueArrayConverter<BTCDatum>))]
public List<BTCDatum> data { get; set; }
public BTCContext context { get; set; }
}
This would ensure it works with both the scenarios you have described.
Upvotes: 2
Reputation: 36
I tried to run your code and I have an exception being throw: Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'ConsoleApp5.BData' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
The simplest way to fix it is to change the BTCRootObject
:
public class BTCRootObject
{
public List<BTCDatum> data { get; set; }
public BTCContext context { get; set; }
}
This way the BTCDatum
is filled correctly.
Upvotes: 0