【问题标题】:C# Getting unnamed list from json web api using JSON.NETC# 使用 JSON.NET 从 json web api 获取未命名列表
【发布时间】:2014-06-21 01:43:45
【问题描述】:

我目前正在使用 JSON.NET 从多个 Web API 获取信息,正如在之前的 q&a. 中向我解释的那样,但现在我偶然发现了另一种我无法解析的 Web API,因为我不不知道怎么做。就是这个:https://data.bter.com/api/1/tickers

如您所见,它是一个 json 交易对集合。但是集合本身是未命名的,所以我必须为每个交易对创建一个类,这并不是真正动态的。我正在使用以下内容来解析网址:

    public static T DownloadSerializedApi<T>(string address) where T : new()
    {
        T newT = new T();
        HttpClient client = new HttpClient();

        using (Stream s = client.GetStreamAsync(address).Result)
        using (StreamReader sr = new StreamReader(s))
        using (JsonReader reader = new JsonTextReader(sr))
        {
            JsonSerializer serializer = new JsonSerializer();

            newT = serializer.Deserialize<T>(reader);
        }

        return newT;
    }

现在我想将 T 设置为“TradingPairs”类,其中会有一个包含所有交易对的列表。但在我现在看来,这将是一长串硬编码对:(

有人愿意帮助我吗? ;)

【问题讨论】:

  • 您是否尝试过仅使用您现在拥有的代码? Json.Net 不应该关心是否有类型名称。
  • 那行不通。我无法制作“Dictionary Pairs”,因为没有什么叫做 Pairs,但必须有一个简单的方法。如果您将该链接放入json2csharp.com,您会发现即使在那里,每一对都有自己的类,但效率并不高:(
  • 您应该能够创建一个具有适当属性的类Pair,并使用JsonProperty 属性将json 映射到这些属性。当我回到办公桌前,我会提供更完整的解决方案。

标签: c# json json.net asp.net-web-api


【解决方案1】:

数据似乎是一个对象字典。你应该返回一本字典。

虽然“东西”可能很难定义。幸运的是,“东西”的许多属性显然是所有人共有的。它们只有两个属性不同。并且这些属性似乎具有从字典的键派生的名称。不是最友好的格式,但可行。

首先我们必须定义类型:

public class Pair
{
    public Tuple<string, string> names { get; set; }
    public Tuple<decimal, decimal> vols { get; set; }

    // common properties
    public bool result { get; set; }
    public decimal last { get; set; }
    public decimal high { get; set; }
    public decimal low { get; set; }
    public decimal avg { get; set; }
    public decimal sell { get; set; }
    public decimal buy { get; set; }
}

还有一个辅助方法:

private Pair CreatePair(string name1, string name2, JObject obj)
{
    var pair = obj.ToObject<Pair>();
    pair.names = Tuple.Create(name1, name2);
    // get the vols from the corresponding properties derived from the names
    pair.vols = Tuple.Create(
        obj.Value<decimal>("vol_" + name1),
        obj.Value<decimal>("vol_" + name2)
    );
    return pair;
}

你可以这样做:

var map = JsonConvert.DeserializeObject<JObject>(json);
var result =
    (from entry in map.Properties()
    let names = entry.Name.Split('_') // get the names
    let obj = entry.Value as JObject
    select CreatePair(names[0], names[1], obj))
    .ToDictionary(x => x.names);

【讨论】:

  • 这也是我要去的地方,除了 vol_btc 成员对于每个条目的命名都不同。他可能需要改为Dictionary&lt;string, Dictionary&lt;string, object&gt;&gt;
  • 嗯,它们都是数字。不一定存储为Number,但 json.net 可以区分。否则,如果这确实是一个问题并且我们需要接受随机对象,您应该更喜欢JObject
  • result 不是数字。
  • 我知道你没有。我的观点是,如果我们使用强类型类Entry 来表示项目,那么我们会错过除一个之外的所有项目的vol_btc,因为名称发生了变化。而且我们不能使用Dictionary&lt;string, decimal&gt; 来表示项目,因为这不适用于result。那么我们就剩下Dictionary&lt;string, object&gt;(或Dictionary&lt;string, JObject&gt;,正如你所建议的那样)。
  • 哦...我现在明白了。但这是有规律的,所以调整它并不是那么棘手。
【解决方案2】:

由于属性名称的变化,这个 JSON 有点棘手,但您仍然应该能够使用您的通用方法来获取数据。

我认为我将采取的方法是创建一个类来表示交易对并使用[JsonExtensionData] 功能来解决每个交易对的vol_xxx 属性名称更改的事实。然后反序列化为Dictionary&lt;string, TradingPair&gt;

下面是定义类的方法:

public class TradingPair
{
    public string result { get; set; }
    public decimal last { get; set; }
    public decimal high { get; set; }
    public decimal low { get; set; }
    public decimal avg { get; set; }
    public decimal sell { get; set; }
    public decimal buy { get; set; }

    [JsonExtensionData]
    private Dictionary<string, object> vols { get; set; }
}

然后像这样反序列化数据:

var tradingPairs = DownloadSerializedApi<Dictionary<string, TradingPair>>(url);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-28
    相关资源
    最近更新 更多