【问题标题】:How to convert API Json response to C# Array?如何将 API Json 响应转换为 C# 数组?
【发布时间】:2019-08-17 07:01:51
【问题描述】:

我正在用 C# 编写一个 Web 服务。为此,我正在对PVGIS 进行 API 调用。 每月太阳辐射值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"

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

【问题讨论】:

  • 您链接的 API 文档中的哪个位置提到了 JSON? (我似乎找不到它被提及。)有一个outputformat 参数接受“csv”(逗号分隔值)或“basic”(“只获取没有文本的数据输出”),后者可能对转换更有用。照原样,您在其上应用 json 序列化程序可能只会将完整的 CSV 转换为长的单个文本字符串,而无需了解其数据结构。如果这些假设是正确的,那么您可能需要为基本的 CSV 响应编写自己的解析结构(或使用库)。祝你好运!
  • 对不起,我错误地提到了 JSON,我已经改变了它。感谢您的建议,我将尝试编写自己的解析结构。
  • 好的。您能否发布您当前使用的完整网址?由于服务根据参数返回不同的数据结构(例如列号),例如this URL(申请“查看源代码”)。

标签: c# arrays json api web-services


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    哇,如果您可以请求 API 以 json 或 xml 进行响应,您可以轻松完成这项工作 - 但如果它真的只是表格文本,那么生活会变得有点复杂,因为您需要手动解析数据并转换把它变成对象。

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

    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";
    

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

    // 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);
        }
    }
    

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

    【讨论】:

      【解决方案3】:

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

      你的班级:

        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 转换回强类型对象是一个不错的选择,应该可以正常工作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-08-02
        • 1970-01-01
        • 2022-06-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多