我正在尝试执行一个函数,该函数返回在Json文件中获得的值的总和。因此,为此,我创建了一个对Json文件进行脱盐处理的模型,如下所示:使用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; }
}
}
反序列化等效果很好。我已经测试过。
在我的控制器中,我有此函数返回总和并引起问题:
[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);
}
我的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"
]
}
]
}
}
您的JSON由包含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();
演示小提琴here。
注意:
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);
}
演示小提琴#2 here。
请参见When should one use dynamic keyword in c# 4.0?,Is the use of dynamic considered a bad practice?和What is the 'dynamic' type in C# 4.0 used for?有关何时使用和不使用dynamic
的进一步讨论。
您的CpuUsageResponse
数据模型对于提供的JSON看起来是正确的。
除了构建自己的自定义NumberFormatInfo
外,您还可以使用NumberFormatInfo
。