【问题标题】:Proper JSON parsing [duplicate]正确的 JSON 解析 [重复]
【发布时间】:2014-07-10 22:09:06
【问题描述】:

我正在为返回 JSON 字符串的 REST 服务开发一个适配器,我想知道是否有更好/更有效的方法来做我正在做的事情。我现在正在做的事情目前有效,但似乎有点偏离,因为有嵌套的 foreach 循环。我正在使用 JSON.net,这是一个控制台应用程序:

这是返回的 JSON:

{"skillsMetrics":{"201":{"avgTimeToAbandon":0,"totalTimeToAnswer":223,"totalTimeToAbandon":0,"enteredQEng":5,"avgTimeToAnswer":45,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":5}},"metricsTotals":{"avgTimeToAbandon":0,"totalTimeToAnswer":223,"totalTimeToAbandon":0,"enteredQEng":5,"avgTimeToAnswer":45,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":5}}

所以问题在于,在这种情况下,“201”是一个 ID 字段,会随着技能的变化而变化。

所以正如我所说,这段代码可以运行,但嵌套的 foreach 循环似乎不在良好的编码标准范围内,但我对如何做到这一点有点茫然。

这是我的 C#:

using (var reader = new StreamReader(response.GetResponseStream()))
{
    var r = reader.ReadToEnd();
    var parsedO = JObject.Parse(r);


    foreach (var item in parsedO)
    {
        var i = item.Key;
        var f = item.Value;

        var parsedO2 = JObject.Parse(f.ToString());

        foreach (var item1 in parsedO2)
        {
            var qHealth = new QueueHealth
            {
                SkillId = item1.Key,
                avgTimeToAbandon = item1.Value.SelectToken("avgTimeToAbandon").Value<dynamic>(),
                totalTimeToAnswer = item1.Value.SelectToken("totalTimeToAnswer").Value<dynamic>(),
                totalTimeToAbandon = item1.Value.SelectToken("totalTimeToAbandon").Value<dynamic>(),
                enteredQEng = item1.Value.SelectToken("enteredQEng").Value<dynamic>(),
                avgTimeToAnswer = item1.Value.SelectToken("avgTimeToAnswer").Value<dynamic>(),
                abandonmentRate = item1.Value.SelectToken("abandonmentRate").Value<dynamic>(),
                abandonedEng = item1.Value.SelectToken("abandonedEng").Value<dynamic>(),
                connectedEng = item1.Value.SelectToken("connectedEng").Value<dynamic>()
            };
        }
    }

编辑:

我也忘了把我的课放在这里。挑战是我需要传递该 SkillID 以便在房屋的数据库端进行一些数据聚合等。数据将用于报告工具

public class QueueHealth
{
    public string SkillId { get; set; }
    public int avgTimeToAbandon { get; set; }
    public int totalTimeToAnswer { get; set; }
    public int totalTimeToAbandon { get; set; }
    public int enteredQEng { get; set; }
    public int avgTimeToAnswer { get; set; }
    public double abandonmentRate { get; set; }
    public int abandonedEng { get; set; }
    public int connectedEng { get; set; }
}

public class QueueHealthContext : DbContext
{
    public QueueHealthContext() : base(ConfigWrapper.AppConnectionString) { }
    public DbSet<QueueHealth> QueuHealthTemp { get; set; }
}

}

这是返回的多重技能 JSON:

{"skillsMetrics":{"64":{"avgTimeToAbandon":0,"totalTimeToAnswer":56,"totalTimeToAbandon":0,"enteredQEng":19,"avgTimeToAnswer":3,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":19},"201":{"avgTimeToAbandon":0,"totalTimeToAnswer":470,"totalTimeToAbandon":0,"enteredQEng":5,"avgTimeToAnswer":67,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":7},"65":{"avgTimeToAbandon":0,"totalTimeToAnswer":56,"totalTimeToAbandon":0,"enteredQEng":5,"avgTimeToAnswer":11,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":5},"66":{"avgTimeToAbandon":0,"totalTimeToAnswer":3,"totalTimeToAbandon":0,"enteredQEng":2,"avgTimeToAnswer":2,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":2},"202":{"avgTimeToAbandon":0,"totalTimeToAnswer":19,"totalTimeToAbandon":0,"enteredQEng":5,"avgTimeToAnswer":4,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":5},"199":{"avgTimeToAbandon":932,"totalTimeToAnswer":2802,"totalTimeToAbandon":2796,"enteredQEng":5,"avgTimeToAnswer":934,"abandonmentRate":0.5,"abandonedEng":3,"connectedEng":3},"198":{"avgTimeToAbandon":203,"totalTimeToAnswer":10488,"totalTimeToAbandon":405,"enteredQEng":178,"avgTimeToAnswer":62,"abandonmentRate":0.01,"abandonedEng":2,"connectedEng":168},"192":{"avgTimeToAbandon":0,"totalTimeToAnswer":41,"totalTimeToAbandon":0,"enteredQEng":3,"avgTimeToAnswer":10,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":4},"194":{"avgTimeToAbandon":0,"totalTimeToAnswer":2,"totalTimeToAbandon":0,"enteredQEng":1,"avgTimeToAnswer":2,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":1},"100":{"avgTimeToAbandon":0,"totalTimeToAnswer":68,"totalTimeToAbandon":0,"enteredQEng":19,"avgTimeToAnswer":3,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":20},"169":{"avgTimeToAbandon":0,"totalTimeToAnswer":2497,"totalTimeToAbandon":0,"enteredQEng":55,"avgTimeToAnswer":47,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":53},"168":{"avgTimeToAbandon":10,"totalTimeToAnswer":1728,"totalTimeToAbandon":10,"enteredQEng":37,"avgTimeToAnswer":48,"abandonmentRate":0.03,"abandonedEng":1,"connectedEng":36},"101":{"avgTimeToAbandon":0,"totalTimeToAnswer":0,"totalTimeToAbandon":0,"enteredQEng":1,"avgTimeToAnswer":0,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":1},"175":{"avgTimeToAbandon":0,"totalTimeToAnswer":5837,"totalTimeToAbandon":0,"enteredQEng":4,"avgTimeToAnswer":1459,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":4},"174":{"avgTimeToAbandon":1201,"totalTimeToAnswer":2144,"totalTimeToAbandon":1201,"enteredQEng":3,"avgTimeToAnswer":1072,"abandonmentRate":0.33,"abandonedEng":1,"connectedEng":2},"96":{"avgTimeToAbandon":0,"totalTimeToAnswer":18,"totalTimeToAbandon":0,"enteredQEng":5,"avgTimeToAnswer":4,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":5},"97":{"avgTimeToAbandon":0,"totalTimeToAnswer":352,"totalTimeToAbandon":0,"enteredQEng":4,"avgTimeToAnswer":70,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":5},"167":{"avgTimeToAbandon":40,"totalTimeToAnswer":8661,"totalTimeToAbandon":40,"enteredQEng":140,"avgTimeToAnswer":62,"abandonmentRate":0.01,"abandonedEng":1,"connectedEng":140},"46":{"avgTimeToAbandon":0,"totalTimeToAnswer":87,"totalTimeToAbandon":0,"enteredQEng":33,"avgTimeToAnswer":2,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":38},"45":{"avgTimeToAbandon":0,"totalTimeToAnswer":74,"totalTimeToAbandon":0,"enteredQEng":24,"avgTimeToAnswer":2,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":30},"55":{"avgTimeToAbandon":352,"totalTimeToAnswer":22025,"totalTimeToAbandon":1407,"enteredQEng":396,"avgTimeToAnswer":55,"abandonmentRate":0.01,"abandonedEng":4,"connectedEng":402},"59":{"avgTimeToAbandon":0,"totalTimeToAnswer":1463,"totalTimeToAbandon":0,"enteredQEng":39,"avgTimeToAnswer":37,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":40},"57":{"avgTimeToAbandon":0,"totalTimeToAnswer":3069,"totalTimeToAbandon":0,"enteredQEng":44,"avgTimeToAnswer":68,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":45},"56":{"avgTimeToAbandon":0,"totalTimeToAnswer":6740,"totalTimeToAbandon":0,"enteredQEng":114,"avgTimeToAnswer":58,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":116},"182":{"avgTimeToAbandon":0,"totalTimeToAnswer":6,"totalTimeToAbandon":0,"enteredQEng":3,"avgTimeToAnswer":2,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":3},"62":{"avgTimeToAbandon":0,"totalTimeToAnswer":871,"totalTimeToAbandon":0,"enteredQEng":1,"avgTimeToAnswer":871,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":1},"61":{"avgTimeToAbandon":0,"totalTimeToAnswer":2015,"totalTimeToAbandon":0,"enteredQEng":1,"avgTimeToAnswer":672,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":3},"180":{"avgTimeToAbandon":0,"totalTimeToAnswer":6,"totalTimeToAbandon":0,"enteredQEng":3,"avgTimeToAnswer":2,"abandonmentRate":0.0,"abandonedEng":0,"connectedEng":3},"60":{"avgTimeToAbandon":849,"totalTimeToAnswer":11973,"totalTimeToAbandon":3394,"enteredQEng":16,"avgTimeToAnswer":1330,"abandonmentRate":0.31,"abandonedEng":4,"connectedEng":9}},"metricsTotals":{"avgTimeToAbandon":578,"totalTimeToAnswer":83569,"totalTimeToAbandon":9253,"enteredQEng":1165,"avgTimeToAnswer":71,"abandonmentRate":0.01,"abandonedEng":16,"connectedEng":1170}}

【问题讨论】:

  • 哇!乔恩斯基特编辑这篇文章!我最好密切关注...
  • 它的工作方式是创建一个自定义类(如QueueHealth)并使用 json 字段为其属性赋予属性,从而有效地进行映射。然后它将直接反序列化到您的对象中。
  • @Darek,如果你拼错 Jon 的名字,你就不能成为粉丝。 ;)
  • 该死的自动更正对我做了这个...@paqogomez
  • 我现在也添加了我的课程代码。问题是如何将 SkillID 放入该类。或者我是否将其作为一个单独的类,并将其他部分作为其属性...

标签: c# .net json deserialization


【解决方案1】:

我会反序列化为具体的类

var obj = JsonConvert.DeserializeObject<MyObject>(json);

public class MyObject
{
    public Dictionary<string,Item> SkillsMetrics { set; get; }
    public Item MetricsTotals { set; get; }
}

public class Item
{
    public int avgTimeToAbandon { get; set; }
    public int totalTimeToAnswer { get; set; }
    public int totalTimeToAbandon { get; set; }
    public int enteredQEng { get; set; }
    public int avgTimeToAnswer { get; set; }
    public double abandonmentRate { get; set; }
    public int abandonedEng { get; set; }
    public int connectedEng { get; set; }
}

编辑

foreach (var item in obj.SkillsMetrics)
{
    Console.WriteLine("SkillId:" + item.Key + " => " + item.Value.totalTimeToAnswer);
}

【讨论】:

  • 我有类似的东西,但我如何将 SkillID 也加入其中?感谢您的回复!
  • 确实,这是正确的做法——也许添加一些专门的 JSON 注释,验证输入并稳定输出,JSON 是非常有用的工具——尤其是像这样的库
  • 我也非常喜欢反序列化具体类。只有当输入变化很大并且我需要在运行时决定如何处理它时,我才会进行更动态的解析。
  • @user3565811 试试代码,SkillID 在 SkillsMetrics 的 Keys 中。 (是Dictionary&lt;string,YourClass&gt;
  • @EZI 我试过了。它做所有事情,但将 SkillID 传递给 Object。
【解决方案2】:

所以我使用了 Newtonsoft 的 Json 转换器来获取动态对象:

        string s =
            @"{""skillsMetrics"":{""201"":{""avgTimeToAbandon"":0,""totalTimeToAnswer"":223,""totalTimeToAbandon"":0,""enteredQEng"":5,""avgTimeToAnswer"":45,""abandonmentRate"":0.0,""abandonedEng"":0,""connectedEng"":5}},""metricsTotals"":{""avgTimeToAbandon"":0,""totalTimeToAnswer"":223,""totalTimeToAbandon"":0,""enteredQEng"":5,""avgTimeToAnswer"":45,""abandonmentRate"":0.0,""abandonedEng"":0,""connectedEng"":5}}";
        dynamic d = JsonConvert.DeserializeObject(s);

有趣的是,它最终以可枚举的两个元素或两个属性结束。

因此,如果您的具体类实现将遵循动态生成的内容,那么反序列化应该不会有问题。

但是,我想我理解您的问题,您有一个名为“201”的“属性”,或者给出的任何其他数字。

有什么方法可以让 JSON 结果更可预测?

【讨论】:

  • 不幸的是,这是来自开发此 API 的第 3 方,我只是在帮助将数据放入数据库。数据格式永远是这样的。最大的问题是我需要“201”作为数据的标识符。我已经添加了 JSON 的样子,这里返回了多个结果集:
  • 我赞成这个答案,因为我最近遇到了一种情况,即第 3 方服务从我们下面更改了 json 对象,这破坏了我(和其他人的)应用程序。并不是说这会发生在你身上,但如果它确实将这种动态对象技术保留在你的后袋中。
猜你喜欢
  • 2021-01-17
  • 2021-12-13
  • 2016-06-24
  • 1970-01-01
  • 2021-12-19
  • 2016-07-18
  • 1970-01-01
  • 2023-03-29
  • 1970-01-01
相关资源
最近更新 更多