如何将 API Json 响应转换为 C# 数组?

How to convert API Json response to C# Array?

我正在用 C# 编写 Web 服务。为此,我正在 API 调用 PVGIS. This API documentation 以获取 每月太阳辐射值 指定它使用 BASIC TEXT 数据或 CSV 数据进行响应,但 API 响应在任何情况下都给出表格视图。我需要将此响应转换为 C# 数组或对象。

我已经尝试了人们在回答其他类似问题时指定的所有方法。

API 回复:

Latitude (decimal degrees): 45.000
Longitude (decimal degrees):    8.000
Radiation database: PVGIS-CMSAF
Optimal slope angle (deg.): 

Year         Month      Hh
2005        Jan     56.5
2005        Feb     75.7
2005        Mar     118
2005        Apr     131
2005        May     193
2005        Jun     211
2005        Jul     217
2005        Aug     179
2005        Sep     115
2005        Oct     72.9
2005        Nov     42.4
2005        Dec     39.4
2006        Jan     51.3
2006        Feb     58.6
2006        Mar     118
2006        Apr     147
2006        May     167
2006        Jun     215
...

我正在使用这个一段代码


    JavaScriptSerializer ser = new JavaScriptSerializer();
    string json = ser.Serialize(response.Content);

我得到的回复是

"Latitude (decimal degrees):\t0.000\r\nLongitude (decimal degrees):\t0.000\r\nRadiation database:\tPVGIS-CMSAF\r\nOptimal slope angle (deg.):\t\r\n\r\nYear\t\t Month\t\tHh\r\n2005\t\tJan\t\t0\r\n2005\t\tFeb\t\t0\r\n2005\t\tMar\t\t0\r\n2005\t\tApr\t\t0\r\n2005\t\tMay\t\t0\r\n2005\t\tJun\t\t0\r\n2005\t\tJul\t\t0\r\n2005\t\tAug\t\t0\r\n2005\t\tSep\t\t0\r\n2005\t\tOct\t\t0\r\n2005\t\tNov\t\t0\r\n2005\t\tDec\t\t0\r\n2006\t\tJan\t\t0\r\n2006\t\tFeb\t\t0\r\n2006\t\tMar\t\t0\r\n2006\t\tApr\t\t0\r\n2006\t\tMay\t\t0\r\n2006\t\tJun\t\t0\r\n2006\t\tJul\t\t0\r\n2006\t\tAug\t\t0\r\n2006\t\tSep\t\t0\r\n2006\t\tOct\t\t0\r\n2006\t\tNov\t\t0\r\n2006\t\tDec\t\t0\r\n2007\t\tJan\t\t0\r\n2007\t\tFeb\t\t0\r\n2007\t\tMar\t\t0\r\n2007\t\tApr\t\t0\r\n2007\t\tMay\t\t0\r\n2007\t\tJun\t\t0\r\n2007\t\tJul\t\t0\r\n2007\t\tAug\t\t0\r\n2007\t\tSep\t\t0\r\n2007\t\tOct\t\t0\r\n2007\t\tNov\t\t0\r\n2007\t\tDec\t\t0\r\n2008\t\tJan\t\t0\r\n2008\t\tFeb\t\t0\r\n2008\t\tMar\t\t0\r\n2008\t\tApr\t\t0\r\n2008\t\tMay\t\t0\r\n2008\t\tJun\t\t0\r\n2008\t\tJul\t\t0\r\n2008\t\tAug\t\t0\r\n2008\t\tSep\t\t0\r\n2008\t\tOct\t\t0\r\n2008\t\tNov\t\t0\r\n2008\t\tDec\t\t0\r\n2009\t\tJan\t\t0\r\n2009\t\tFeb\t\t0\r\n2009\t\tMar\t\t0\r\n2009\t\tApr\t\t0\r\n2009\t\tMay\t\t0\r\n2009\t\tJun\t\t0\r\n2009\t\tJul\t\t0\r\n2009\t\tAug\t\t0\r\n2009\t\tSep\t\t0\r\n2009\t\tOct\t\t0\r\n2009\t\tNov\t\t0\r\n2009\t\tDec\t\t0\r\n2010\t\tJan\t\t0\r\n2010\t\tFeb\t\t0\r\n2010\t\tMar\t\t0\r\n2010\t\tApr\t\t0\r\n2010\t\tMay\t\t0\r\n2010\t\tJun\t\t0\r\n2010\t\tJul\t\t0\r\n2010\t\tAug\t\t0\r\n2010\t\tSep\t\t0\r\n2010\t\tOct\t\t0\r\n2010\t\tNov\t\t0\r\n2010\t\tDec\t\t0\r\n2011\t\tJan\t\t0\r\n2011\t\tFeb\t\t0\r\n2011\t\tMar\t\t0\r\n2011\t\tApr\t\t0\r\n2011\t\tMay\t\t0\r\n2011\t\tJun\t\t0\r\n2011\t\tJul\t\t0\r\n2011\t\tAug\t\t0\r\n2011\t\tSep\t\t0\r\n2011\t\tOct\t\t0\r\n2011\t\tNov\t\t0\r\n2011\t\tDec\t\t0\r\n2012\t\tJan\t\t0\r\n2012\t\tFeb\t\t0\r\n2012\t\tMar\t\t0\r\n2012\t\tApr\t\t0\r\n2012\t\tMay\t\t0\r\n2012\t\tJun\t\t0\r\n2012\t\tJul\t\t0\r\n2012\t\tAug\t\t0\r\n2012\t\tSep\t\t0\r\n2012\t\tOct\t\t0\r\n2012\t\tNov\t\t0\r\n2012\t\tDec\t\t0\r\n2013\t\tJan\t\t0\r\n2013\t\tFeb\t\t0\r\n2013\t\tMar\t\t0\r\n2013\t\tApr\t\t0\r\n2013\t\tMay\t\t0\r\n2013\t\tJun\t\t0\r\n2013\t\tJul\t\t0\r\n2013\t\tAug\t\t0\r\n2013\t\tSep\t\t0\r\n2013\t\tOct\t\t0\r\n2013\t\tNov\t\t0\r\n2013\t\tDec\t\t0\r\n2014\t\tJan\t\t0\r\n2014\t\tFeb\t\t0\r\n2014\t\tMar\t\t0\r\n2014\t\tApr\t\t0\r\n2014\t\tMay\t\t0\r\n2014\t\tJun\t\t0\r\n2014\t\tJul\t\t0\r\n2014\t\tAug\t\t0\r\n2014\t\tSep\t\t0\r\n2014\t\tOct\t\t0\r\n2014\t\tNov\t\t0\r\n2014\t\tDec\t\t0\r\n2015\t\tJan\t\t0\r\n2015\t\tFeb\t\t0\r\n2015\t\tMar\t\t0\r\n2015\t\tApr\t\t0\r\n2015\t\tMay\t\t0\r\n2015\t\tJun\t\t0\r\n2015\t\tJul\t\t0\r\n2015\t\tAug\t\t0\r\n2015\t\tSep\t\t0\r\n2015\t\tOct\t\t0\r\n2015\t\tNov\t\t0\r\n2015\t\tDec\t\t0\r\nHh: Irradiation on horizontal plane  (kWh/m2)\r\n\r\nPVGIS (c) European Communities, 2001-2016"

我希望输出是 JSON 对象,我可以将其转换为 C# 对象,或者如果可能,将响应直接转换为 C# 数组或对象。

一些网络服务以多种格式呈现数据。因此 http 请求可以说明它需要哪种数据类型,而 Web 服务将提供该格式的数据。 https://restfulapi.net/content-negotiation/

对于您的问题,我想如果您将 header "Accept: application/json" 添加到您的 http 请求中,Web 服务将为您提供 json 格式的数据。

鉴于您已经在使用 ToObject,考虑简化代码以提高可读性和无需转换任何内容的优势,您可以在您的情况下创建一个 class 和 3 属性并使用此代码( 您应该记住,这些字段是根据 Json 输出使用 class 属性构建的:

your Class:

  public class Monthly
    {
        public string Year { get; set; }
        public string Month { get; set; }
        public string  Hh { get; set; }
    }

var contentJson = await SendRequest(request);
dynamic response = JsonConvert.DeserializeObject(contentJson); 
List<Monthly> organizations = response.organizations.ToObject<List<Monthly>>();

实际响应似乎无关紧要,因此使用动态可以简化事情。通过调用 ToObject 转换回强类型对象是一个不错的选择,应该会很好。

哇,如果您可以请求 API 以 json 或 xml 进行响应,您就可以快速解决这个问题 - 但如果它真的只是表格文本,那么生活就会变得有点复杂,因为您需要手动解析数据并将其转换为对象。

让我们考虑一个您可能定位的示例对象,其中包含另一个自定义类型的集合。 (为方便起见,我们使用了列表,因为我们可能不知道预期数据的长度,如果愿意,您可以用它代替 HashSet,或者甚至稍微交换一下,使它成为一个私有集合,使用 public 方法 returns 如果数组是你需要使用的,它作为一个数组。你也可以根据需要更改成员类型。

public class ApiData
{
    public decimal Latitude { get; set; }
    public decimal Longitude { get; set; }
    public string RadiationDatabase { get; set; }
    public List<ApiSlopeAngle> OptimalSlopeAngle { get; set; }

    public ApiData()
    {
        OptimalSlopeAngle = new List<ApiSlopeAngle>();
    }
}

这是嵌套对象。

public class ApiSlopeAngle
{
    public int Year { get; set; }
    public string Month { get; set; }
    public decimal Hh { get; set; }
    public ApiSlopeAngle(int year, string month, decimal hh)
    {
        Year = year;
        Month = month;
        Hh = hh;
    }
}

这是一些缩短的示例数据。

// Sample data
string apiStringData = "Latitude (decimal degrees):\t45.000\r\nLongitude (decimal degrees):\t8.000\r\nRadiation database:\tPVGIS-CMSAF\r\nOptimal slope angle (deg.):\t\r\n\r\nYear\t\t Month\t\tHh\r\n2005\t\tJan\t\t56.5\r\n2005\t\tFeb\t\t75.7\r\n2005\t\tMar\t\t118\r\n2005\t\tApr\t\t131\r\n2005\t\tMay\t\t193\r\n2005\t\tJun\t\t211\r\n2005\t\tJul\t\t217\r\n2005\t\tAug\t\t179\r\n2005\t\tSep\t\t115\r\n2005\t\tOct\t\t72.9\r\n2005\t\tNov\t\t42.4\r\nHh: Irradiation on horizontal plane(kWh/ m2)\r\n\r\nPVGIS(c) European Communities, 2001 - 2016";

现在用 Regex 解析示例数据....免责声明 - 代码仅作为示例,包含最少的检查,假定数据格式是一致的。我的正则表达式也很基础!

// Define the regex patterns to use
string lattPattern = "(Latitude\s\(decimal\sdegrees\):)(\t\d+\.*\d*)";
string longPattern = "(Longitude\s\(decimal\sdegrees\):)(\t\d+\.*\d*)";
string radDbPattern = "(Radiation\sdatabase\:)(\t)(PVGIS\-CMSAF)";
string osaPattern = "((19|20)\d{2})(\t\t)([A-Z]+[a-z]*)(\t\t\d+\.*\d*)";

// Create the matches for the top-level data
var lattitude = Regex.Match(apiStringData, lattPattern);
var longitude = Regex.Match(apiStringData, longPattern);
var radDb = Regex.Match(apiStringData, radDbPattern);

// Create the result object, and populate the top-level properties
ApiData apiObject = new ApiData();
apiObject.Latitude = Convert.ToDecimal(lattitude.Groups[2].ToString());
apiObject.Longitude = Convert.ToDecimal(longitude.Groups[2].ToString());
apiObject.RadiationDatabase = radDb.Groups[3].ToString();

// Split the sample data into an array 
// to make it easier to enumerate what will become the nested data
string[] apiArray = Regex.Split(apiStringData, "\r\n");

// Step through it
foreach (string s in apiArray)
{
    var angle = Regex.Match(s, osaPattern, RegexOptions.IgnoreCase);
    if (angle.Success == true)
    {
        // Create the properties
        int year = Convert.ToInt32(angle.Groups[1].ToString());
        string month = angle.Groups[4].ToString();
        decimal hh = Convert.ToDecimal(angle.Groups[5].ToString());

        // Add to the collection
        ApiSlopeAngle apiDate = new ApiSlopeAngle(year, month, hh);
        apiObject.OptimalSlopeAngle.Add(apiDate);
    }
}

再次强调,这里有很大的改进空间,很高兴任何人都能做得更好!