使用JsonConvert在JSON中反序列化一致数组?

时间:2018-02-09 07:53:01

标签: c# json

我尝试使用Prometheus监控工具,并在我查询的某些指标中提供以下响应:

{
    "status": "success",
    "data": {
        "resultType": "matrix",
        "result": [{
            "metric": {
                "__name__": "node_cpu",
                "cpu": "cpu0",
                "instance": "localhost:9100",
                "job": "node",
                "mode": "guest"
            },
            "values": [
                [1518164248.959, "0"],
                [1518164263.959, "0"],
                [1518164278.959, "0"],
                [1518164293.959, "0"],
                [1518164308.959, "0"]
            ]
        }, {
            "metric": {
                "__name__": "node_cpu",
                "cpu": "cpu0",
                "instance": "localhost:9100",
                "job": "node",
                "mode": "guest_nice"
            },
            "values": [
                [1518164248.959, "0"],
                [1518164263.959, "0"],
                [1518164278.959, "0"],
                [1518164293.959, "0"],
                [1518164308.959, "0"]
            ]
        }, {
            "metric": {
                "__name__": "node_cpu",
                "cpu": "cpu0",
                "instance": "localhost:9100",
                "job": "node",
                "mode": "idle"
            },
            "values": [
                [1518164248.959, "11969.01"],
                [1518164263.959, "11983.93"],
                [1518164278.959, "11998.83"],
                [1518164293.959, "12013.73"],
                [1518164308.959, "12028.64"]
            ]
        }, {
            "metric": {
                "__name__": "node_cpu",
                "cpu": "cpu0",
                "instance": "localhost:9100",
                "job": "node",
                "mode": "iowait"
            },
            "values": [
                [1518164248.959, "29.2"],
                [1518164263.959, "29.21"],
                [1518164278.959, "29.21"],
                [1518164293.959, "29.22"],
                [1518164308.959, "29.23"]
            ]
        }, {
            "metric": {
                "__name__": "node_cpu",
                "cpu": "cpu0",
                "instance": "localhost:9100",
                "job": "node",
                "mode": "irq"
            },
            "values": [
                [1518164248.959, "0"],
                [1518164263.959, "0"],
                [1518164278.959, "0"],
                [1518164293.959, "0"],
                [1518164308.959, "0"]
            ]
        }, {
            "metric": {
                "__name__": "node_cpu",
                "cpu": "cpu0",
                "instance": "localhost:9100",
                "job": "node",
                "mode": "nice"
            },
            "values": [
                [1518164248.959, "2.49"],
                [1518164263.959, "2.49"],
                [1518164278.959, "2.49"],
                [1518164293.959, "2.49"],
                [1518164308.959, "2.49"]
            ]
        }, {
            "metric": {
                "__name__": "node_cpu",
                "cpu": "cpu0",
                "instance": "localhost:9100",
                "job": "node",
                "mode": "softirq"
            },
            "values": [
                [1518164248.959, "1.47"],
                [1518164263.959, "1.48"],
                [1518164278.959, "1.48"],
                [1518164293.959, "1.48"],
                [1518164308.959, "1.48"]
            ]
        }, {
            "metric": {
                "__name__": "node_cpu",
                "cpu": "cpu0",
                "instance": "localhost:9100",
                "job": "node",
                "mode": "steal"
            },
            "values": [
                [1518164248.959, "0"],
                [1518164263.959, "0"],
                [1518164278.959, "0"],
                [1518164293.959, "0"],
                [1518164308.959, "0"]
            ]
        }, {
            "metric": {
                "__name__": "node_cpu",
                "cpu": "cpu0",
                "instance": "localhost:9100",
                "job": "node",
                "mode": "system"
            },
            "values": [
                [1518164248.959, "34.36"],
                [1518164263.959, "34.38"],
                [1518164278.959, "34.41"],
                [1518164293.959, "34.44"],
                [1518164308.959, "34.46"]
            ]
        }, {
            "metric": {
                "__name__": "node_cpu",
                "cpu": "cpu0",
                "instance": "localhost:9100",
                "job": "node",
                "mode": "user"
            },
            "values": [
                [1518164248.959, "40.93"],
                [1518164263.959, "40.96"],
                [1518164278.959, "41"],
                [1518164293.959, "41.05"],
                [1518164308.959, "41.08"]
            ]
        }, {
            "metric": {
                "__name__": "node_cpu",
                "cpu": "cpu1",
                "instance": "localhost:9100",
                "job": "node",
                "mode": "guest"
            },
            "values": [
                [1518164248.959, "0"],
                [1518164263.959, "0"],
                [1518164278.959, "0"],
                [1518164293.959, "0"],
                [1518164308.959, "0"]
            ]
        }, {
            "metric": {
                "__name__": "node_cpu",
                "cpu": "cpu1",
                "instance": "localhost:9100",
                "job": "node",
                "mode": "guest_nice"
            },
            "values": [
                [1518164248.959, "0"],
                [1518164263.959, "0"],
                [1518164278.959, "0"],
                [1518164293.959, "0"],
                [1518164308.959, "0"]
            ]
        }, {
            "metric": {
                "__name__": "node_cpu",
                "cpu": "cpu1",
                "instance": "localhost:9100",
                "job": "node",
                "mode": "idle"
            },
            "values": [
                [1518164248.959, "11980.39"],
                [1518164263.959, "11995.32"],
                [1518164278.959, "12010.24"],
                [1518164293.959, "12025.17"],
                [1518164308.959, "12040.07"]
            ]
        }, {
            "metric": {
                "__name__": "node_cpu",
                "cpu": "cpu1",
                "instance": "localhost:9100",
                "job": "node",
                "mode": "iowait"
            },
            "values": [
                [1518164248.959, "30.36"],
                [1518164263.959, "30.36"],
                [1518164278.959, "30.36"],
                [1518164293.959, "30.36"],
                [1518164308.959, "30.36"]
            ]
        }, {
            "metric": {
                "__name__": "node_cpu",
                "cpu": "cpu1",
                "instance": "localhost:9100",
                "job": "node",
                "mode": "irq"
            },
            "values": [
                [1518164248.959, "0"],
                [1518164263.959, "0"],
                [1518164278.959, "0"],
                [1518164293.959, "0"],
                [1518164308.959, "0"]
            ]
        }, {
            "metric": {
                "__name__": "node_cpu",
                "cpu": "cpu1",
                "instance": "localhost:9100",
                "job": "node",
                "mode": "nice"
            },
            "values": [
                [1518164248.959, "0.02"],
                [1518164263.959, "0.02"],
                [1518164278.959, "0.02"],
                [1518164293.959, "0.02"],
                [1518164308.959, "0.02"]
            ]
        }, {
            "metric": {
                "__name__": "node_cpu",
                "cpu": "cpu1",
                "instance": "localhost:9100",
                "job": "node",
                "mode": "softirq"
            },
            "values": [
                [1518164248.959, "0.64"],
                [1518164263.959, "0.64"],
                [1518164278.959, "0.64"],
                [1518164293.959, "0.64"],
                [1518164308.959, "0.64"]
            ]
        }, {
            "metric": {
                "__name__": "node_cpu",
                "cpu": "cpu1",
                "instance": "localhost:9100",
                "job": "node",
                "mode": "steal"
            },
            "values": [
                [1518164248.959, "0"],
                [1518164263.959, "0"],
                [1518164278.959, "0"],
                [1518164293.959, "0"],
                [1518164308.959, "0"]
            ]
        }, {
            "metric": {
                "__name__": "node_cpu",
                "cpu": "cpu1",
                "instance": "localhost:9100",
                "job": "node",
                "mode": "system"
            },
            "values": [
                [1518164248.959, "22.17"],
                [1518164263.959, "22.18"],
                [1518164278.959, "22.2"],
                [1518164293.959, "22.22"],
                [1518164308.959, "22.24"]
            ]
        }, {
            "metric": {
                "__name__": "node_cpu",
                "cpu": "cpu1",
                "instance": "localhost:9100",
                "job": "node",
                "mode": "user"
            },
            "values": [
                [1518164248.959, "34.07"],
                [1518164263.959, "34.09"],
                [1518164278.959, "34.1"],
                [1518164293.959, "34.11"],
                [1518164308.959, "34.16"]
            ]
        }]
    }
}

我试图将其反序列化为一个对象,除了本节之外这是有效的:

"values": [
    [1518164248.959, "0"],
    [1518164263.959, "0"],
    [1518164278.959, "0"],
    [1518164293.959, "0"],
    [1518164308.959, "0"]
]

它反序列化,但value始终为null

我认为这是因为我错误地通过对象解释了这些数据。这就是我所拥有的:

public class CpuMetrics
{
    public string status { get; set; }
    public CpuData data { get; set; }
}

public class CpuData
{
    public string resultType { get; set; }
    public List<Result> result { get; set; }
}

public class Result
{
    public Metric metric { get; set; }
    public List<object> value { get; set; }
}

public class Metric
{
    public string __name__ { get; set; }
    public string cpu { get; set; }
    public string instance { get; set; }
    public string job { get; set; }
    public string mode { get; set; }
}

返回null的对象示例:

Visual studio Screenshot

由于此数据始终一致,我认为在这种情况下我不必创建自定义JsonConverter。我错了吗?我应该创建自己的JsonConverter扩展来管理这些特定字段吗?

2 个答案:

答案 0 :(得分:2)

这是一个工作版本。我使用了https://app.quicktype.io/#l=cs&r=json2csharp

生成对象模型。请注意值反序列化中的类型处理。

using System;
using System.Collections.Generic;
using System.Net;
using Newtonsoft.Json;

namespace ConsoleApp2
{
    public class Program
    {
        public static void Main()
        {
            string json =
                "{ \"status\": \"success\", \"data\": { \"resultType\": \"vector\", \"result\": [ { \"metric\": { \"__name__\": \"node_cpu\", \"cpu\": \"cpu0\", \"instance\": \"localhost:9100\", \"job\": \"node\", \"mode\": \"guest\" }, \"value\": [ 1518159211.958, \"0\" ] }, { \"metric\": { \"__name__\": \"node_cpu\", \"cpu\": \"cpu0\", \"instance\": \"localhost:9100\", \"job\": \"node\", \"mode\": \"guest_nice\" }, \"value\": [ 1518159211.958, \"0\" ] } ] } }";
            var data = VerificationResponse.FromJson(json);
            Console.WriteLine(data);
        }
    }


    public partial class VerificationResponse
    {
        [JsonProperty("status")]
        public string Status { get; set; }

        [JsonProperty("data")]
        public Data Data { get; set; }
    }

    public partial class Data
    {
        [JsonProperty("resultType")]
        public string ResultType { get; set; }

        [JsonProperty("result")]
        public List<Result> Result { get; set; }
    }

    public partial class Result
    {
        [JsonProperty("metric")]
        public Metric Metric { get; set; }

        [JsonProperty("value")]
        public List<Value> Value { get; set; }
    }

    public partial class Metric
    {
        [JsonProperty("__name__")]
        public string Name { get; set; }

        [JsonProperty("cpu")]
        public string Cpu { get; set; }

        [JsonProperty("instance")]
        public string Instance { get; set; }

        [JsonProperty("job")]
        public string Job { get; set; }

        [JsonProperty("mode")]
        public string Mode { get; set; }
    }

    public partial struct Value
    {
        public double? Double;
        public string String;
    }

    public partial class VerificationResponse
    {
        public static VerificationResponse FromJson(string json) => JsonConvert.DeserializeObject<VerificationResponse>(
            json, Converter.Settings);
    }

    public partial struct Value
    {
        public Value(JsonReader reader, JsonSerializer serializer)
        {
            Double = null;
            String = null;

            switch (reader.TokenType)
            {
                case JsonToken.Integer:
                case JsonToken.Float:
                    Double = serializer.Deserialize<double>(reader);
                    return;
                case JsonToken.String:
                case JsonToken.Date:
                    String = serializer.Deserialize<string>(reader);
                    return;
            }
            throw new Exception("Cannot convert Value");
        }

        public void WriteJson(JsonWriter writer, JsonSerializer serializer)
        {
            if (Double != null)
            {
                serializer.Serialize(writer, Double);
                return;
            }
            if (String != null)
            {
                serializer.Serialize(writer, String);
                return;
            }
            throw new Exception("Union must not be null");
        }
    }

    public static class Serialize
    {
        public static string ToJson(this VerificationResponse self) => JsonConvert.SerializeObject(self,
            Converter.Settings);
    }

    public class Converter : JsonConverter
    {
        public override bool CanConvert(Type t) => t == typeof(Value);

        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
        {
            if (t == typeof(Value))
                return new Value(reader, serializer);
            throw new Exception("Unknown type");
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var t = value.GetType();
            if (t == typeof(Value))
            {
                ((Value) value).WriteJson(writer, serializer);
                return;
            }
            throw new Exception("Unknown type");
        }

        public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
        {
            MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
            DateParseHandling = DateParseHandling.None,
            Converters = {new Converter()},
        };
    }
}

答案 1 :(得分:1)

在您上次更新后,我能够重现错误。基本上你的代码中有一个拼写错误。它不是value而是values

public class Result
{
    public Metric metric { get; set; }
    public List<object> values { get; set; }
}