Json.net десерилизация - PullRequest
       74

Json.net десерилизация

1 голос
/ 06 ноября 2019

Я получаю странные результаты, когда пытаюсь десерилизовать объект json в c #. У меня был такой же процесс, чтобы без проблем опустошать другие объекты json, но этот, похоже, дает мне странные результаты. jsonresult в json explorer выглядит нормально, однако я заметил, что он размещает 1,2,3 объекта под данными, которые, как я предполагал, список поймает. но я все еще получаю null для некоторых объектов.

У меня есть следующий объект 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);

Вот код json для муравейника после 0 блоков: я понятия не имею, как обрабатывать 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 ]

2 голосов
/ 06 ноября 2019

Пожалуйста, обратитесь к разделу обновления.

Проблема 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, в которой inturn содержит коллекцию BTCDatum.

Это необходимо исправить следующим образом:

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

Обновление: на основе редактирования в OP

Проблема 2: Сбор и объект для данных Вторая проблема заключается в том, что data может быть массивом или объектом на основе двух предоставленных вами образцов Json. Чтобы справиться с этим, вы можете создать JsonConverter, который преобразует отдельный объект в коллекцию. Например,

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 должно быть длинным вместо Int, как показано во втором примере Json, который вы предоставили.

Ваша окончательная структура данных будет выглядеть следующим образом.

[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гарантирует, что он будет работать с обоими сценариями, которые вы описали.

0 голосов
/ 06 ноября 2019

Я попытался запустить ваш код, и у меня возникло исключение 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.

Самый простой способ исправить это - изменить BTCRootObject:

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

Thisкак BTCDatum заполнен правильно.

...