Json.net反序列化

时间:2019-11-06 10:40:01

标签: c# json.net json-deserialization

在C#中尝试对json对象进行反序列化时,我得到了奇怪的结果,我已经在相同的过程中对其他json对象进行了反序列化,没有问题,但这似乎给了我奇怪的结果。 json资源管理器中的jsonresult看起来不错,但是我注意到它将1,2,3对象放置在我认为列表会捕获此数据的数据下。但我仍然收到某些对象的空值。

我有以下json对象。

{
"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:info@blockchair.com)"
    }
}

}

我在测试时创建的类是:

[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;
}

当我尝试获取结果上下文时,BData很好,但BTCDatum为空! 这是Json.net库中使用的代码。

string jsonresult = System.Text.Encoding.UTF8.GetString(www.downloadHandler.data);

                BTCRootObject BTC_Block = JsonConvert.DeserializeObject<BTCRootObject>(jsonresult);

这里是0块之后的json:我不知道如何处理1,2等。

{
"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:info@blockchair.com)"
    }
}

}

2 个答案:

答案 0 :(得分:2)

请参阅更新部分。

问题1:BTCRootObject的定义错误

您的问题在于BTCRootObject的定义。根据OP,BTCRootObject定义为

[System.Serializable]
public class BTCRootObject
{    
    public BData data { get; set; }
    public BTCContext context { get; set; }
}
[System.Serializable]
public class BData
{   
    public List<BTCDatum> datrum;
}

如果检查JSON,则可以看到根对象包含一个BTCDatum数组,但是根据OP中提供的代码,它包含一个BData实例,而该实例又包含BTCDatum的集合。

这需要按以下说明纠正

[System.Serializable]
public class BTCRootObject
{    
    public List<BTCDatum> data { get; set; }
    public BTCContext context { get; set; }
}

更新:基于OP中的编辑

问题2:数据的收集和对象 第二个问题是基于您提供的两个示例Json,data可以是数组或对象。为了解决这个问题,您可以创建一个JsonConverter,它将一个Single Object转换为一个集合。例如,

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; }
    }
}

现在您可以将BTCRootObject的定义更改为

[System.Serializable]
public class BTCRootObject
{   [JsonConverter(typeof(SingleValueArrayConverter<BTCDatum>))] 
    public List<BTCDatum> data { get; set; }
    public BTCContext context { get; set; }
}

问题3:BTCBlock.nonce需要很长

BTCBlock.nonce属性需要很长,而不是您提供的第二个示例Json中所示的Int。

您的最终数据结构如下所示。

[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; }
}

这将确保它可以与您描述的两种情况一起使用。

答案 1 :(得分:0)

我尝试运行您的代码,但抛出异常: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.

最简单的解决方法是更改​​BTCRootObject

public class BTCRootObject
{
    public List<BTCDatum> data { get; set; }
    public BTCContext context { get; set; }
}

通过这种方式可以正确填充BTCDatum