Не удается прочитать несколько значений из файла Json с функцией c# - PullRequest
2 голосов
/ 10 марта 2020

Я пытаюсь сделать функцию, которая возвращает сумму значений, которые я получаю в файле Json. Поэтому для этого я создал модель для десаризации файла Json, она выглядит следующим образом: using System.Collections.Generic;

namespace ServerMonitoringApi.Controllers.CpuUsage.Model
{
    public class Metric
    {
        public string __name__ { get; set; }
        public string core { get; set; }
        public string instance { get; set; }
        public string job { get; set; }
    }

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

    public class Data
    {
        public string resultType { get; set; }
        public IList<Result> result { get; set; }
    }

    public class CpuUsageResponse
    {
        public string status { get; set; }
        public Data data { get; set; }
    }
}

Он отлично работает для десериализации et c .. I ' Я проверил это.

В моем контроллере у меня есть эта функция, которая возвращает сумму и вызывает проблему:

[HttpGet("Number/{instance}&{port}")]
public async Task<double> GetNumCpuUsagePerInstance(string instance, string port)
{
    string perInstanceLink = MetricApiLink + "{instance=\"" + instance + ":" + port + "\"}";
    string idleModeLink = MetricApiLink +
        "{mode=\"idle\",instance=\"" + instance + ":" + port + "\"}";
    dynamic dataGetAll;
    dynamic dataGetIdle;
    using (var httpClient = new HttpClient())
    {
        using (var response = await httpClient
            .GetAsync(perInstanceLink))
        {
            string apiResponse = await response.Content.ReadAsStringAsync();
            dataGetAll = JsonConvert.DeserializeObject<CpuUsageResponse>(apiResponse);
        }
    }
    using (var httpClient = new HttpClient())
    {
        using (var response = await httpClient
            .GetAsync(idleModeLink))
        {
            string apiResponse = await response.Content.ReadAsStringAsync();
            dataGetIdle = JsonConvert.DeserializeObject<CpuUsageResponse>(apiResponse);
        }
    }

    double sum1 = 0;
    double sum2 = 0;
    NumberFormatInfo provider = new NumberFormatInfo();
    provider.NumberGroupSeparator = ".";

    foreach(CpuUsageResponse x in dataGetAll)
    {
        sum1 += Convert.ToDouble(x.data.result[1].value[1], provider);
    }

    return sum1;
}

Я проверил каждую функцию, они работают нормально, но когда я пытаюсь это сделать " «Foreach» не работает и выдает сообщение об ошибке:

RuntimeBinderException: невозможно неявно преобразовать тип 'ServerMonitoringApi.Controllers.CpuUsage.Model.CpuUsageResponse' в 'System.Collections.IEnumerable'. Существует явное преобразование (вам не хватает приведения?). И скажите, что ошибка в строке 123:

    NumberFormatInfo provider = new NumberFormatInfo();
    provider.NumberGroupSeparator = ".";

    /*here(line 123)->*/ foreach(CpuUsageResponse x in dataGetAll)
    {
        sum1 += Convert.ToDouble(dataGetAll.data.result[1].value[1], provider);
    }

My Json Файл имеет вид:

{
    "status": "success",
    "data": {
        "resultType": "vector",
        "result": [
            {
                "metric": {
                    "__name__": "wmi_cpu_time_total",
                    "core": "0,0",
                    "instance": "192.168.1.101:9182",
                    "job": "Server-monitoring-Api"
                },
                "value": [
                    1583873150.877,
                    "95595.25"
                ]
            },
            {
                "metric": {
                    "__name__": "wmi_cpu_time_total",
                    "core": "0,1",
                    "instance": "192.168.1.101:9182",
                    "job": "Server-monitoring-Api"
                },
                "value": [
                    1583873150.877,
                    "103647.703125"
                ]
            },
            {
                "metric": {
                    "__name__": "wmi_cpu_time_total",
                    "core": "0,2",
                    "instance": "192.168.1.101:9182",
                    "job": "Server-monitoring-Api"
                },
                "value": [
                    1583873150.877,
                    "94185.015625"
                ]
            },
            {
                "metric": {
                    "__name__": "wmi_cpu_time_total",
                    "core": "0,3",
                    "instance": "192.168.1.101:9182",
                    "job": "Server-monitoring-Api"
                },
                "value": [
                    1583873150.877,
                    "102109.203125"
                ]
            },
            {
                "metric": {
                    "__name__": "wmi_cpu_time_total",
                    "core": "0,4",
                    "instance": "192.168.1.101:9182",
                    "job": "Server-monitoring-Api"
                },
                "value": [
                    1583873150.877,
                    "96709.59375"
                ]
            },
            {
                "metric": {
                    "__name__": "wmi_cpu_time_total",
                    "core": "0,5",
                    "instance": "192.168.1.101:9182",
                    "job": "Server-monitoring-Api"
                },
                "value": [
                    1583873150.877,
                    "102046.5625"
                ]
            },
            {
                "metric": {
                    "__name__": "wmi_cpu_time_total",
                    "core": "0,6",
                    "instance": "192.168.1.101:9182",
                    "job": "Server-monitoring-Api"
                },
                "value": [
                    1583873150.877,
                    "98963.453125"
                ]
            },
            {
                "metric": {
                    "__name__": "wmi_cpu_time_total",
                    "core": "0,7",
                    "instance": "192.168.1.101:9182",
                    "job": "Server-monitoring-Api"
                },
                "value": [
                    1583873150.877,
                    "89011.53125"
                ]
            }
        ]
    }
}

Я пытаюсь сложить значения с индексом 1, т.е. value[1] и вернуть его

1 Ответ

2 голосов
/ 11 марта 2020

Ваш JSON состоит из одного root объекта, содержащего массив data.result []:

{
   "status":"success",
   "data":{
      "resultType":"vector",
      "result":[/* Results */]
   }
}

Где каждый результат выглядит следующим образом:

{
    "metric": {
        "__name__": "wmi_cpu_time_total",
        "core": "0,0",
        "instance": "192.168.1.101:9182",
        "job": "Server-monitoring-Api"
    },
    "value": [
        1583851813.666,
        "79186.65625"
    ]
}

Как таковой, цикл через самый внешний контейнер JSON, как вы пытаетесь сделать здесь

foreach(CpuUsageResponse x in dataGetAll)
{
    sum1 += Convert.ToDouble(x.data.result[1].value[1], provider);
}

Не имеет смысла. Если бы самый внешний контейнер JSON был массивом, это было бы разумно.

Вместо этого, если вы хотите сложить все значения data.result[*].value[1] в двойной результат, вы можете сделать это. следующим образом:

CpuUsageResponse dataGetAll;

// Download the apiResponse JSON string (code omitted)

dataGetAll = JsonConvert.DeserializeObject<CpuUsageResponse>(apiResponse);

var sum = dataGetAll.data.result
    .Select(r => r.value[1])
    .Select(s => Convert.ToDouble(s, NumberFormatInfo.InvariantInfo))
    .Sum();

Демонстрационная скрипка здесь .

Примечания:

  • Do not объявить dataGetAll как dynamic. Тем самым вы устраняете все проверки правильности кода во время компиляции и заменяете их ошибками времени выполнения, такими как исключение RuntimeBinderException, показанное в вашем вопросе. Так как вы создали модель данных c#, вы должны использовать ее, и если бы вы это сделали, вы бы получили гораздо более четкую ошибку компиляции:

    CpuUsageResponse dataGetAll;
    
    dataGetAll = JsonConvert.DeserializeObject<CpuUsageResponse>(apiResponse);
    
    double sum1 = 0;
    NumberFormatInfo provider = new NumberFormatInfo();
    provider.NumberGroupSeparator = ".";
    
    //Compilation error (line 63, col 43): foreach statement cannot operate on variables of type 'CpuUsageResponse' because 'CpuUsageResponse' does not contain a public instance definition for 'GetEnumerator'
    foreach(CpuUsageResponse x in dataGetAll)
    {
        sum1 += Convert.ToDouble(x.data.result[1].value[1], provider);
    }   
    

    Demo Fiddle # 2 здесь .

    См. Когда следует использовать ключевое слово Dynami c в c# 4,0? , Рассматривается ли использование Dynami c плохая практика? и Для чего используется «динамический» тип в C# 4.0? для дальнейшего обсуждения того, когда использовать, а не использовать , dynamic.

  • Ваша модель данных CpuUsageResponse выглядит корректно для предоставленной JSON.

  • Вместо того, чтобы создавать свою собственную, Пользовательский NumberFormatInfo, вы можете просто использовать NumberFormatInfo.InvariantInfo.

...