简体   繁体   中英

How to convert API Json response to C# Array?

I'm writing a web service in C#. For that i am making API calls to PVGIS . This API documentation for specifies it responds with BASIC TEXT data or CSV data but the API response gives tabular view in any case. 文档指定它使用BASIC TEXT数据或CSV数据进行响应,但是在任何情况下,API响应均提供表格视图。 I need this response converted to c# array or object.

I've tried all methods people have specified in answers to other similar questions.

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
...

I'm using this


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

And the response i get is

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

I expect the output to be either JSON object that i can convert to C# object or if possible converting response directly to C# array or object.

Some web services present data in multiple formats. So the http request can say which data type it needs and the web service will provide data in that format. https://restfulapi.net/content-negotiation/

For your question I think if you add the header "Accept: application/json" to your http request, the web service will give you data in json format.

Given that you are already using the ToObject, consider simplifying the code for readability and the advantage of not having to convert anything, you can just create a class with 3 property in your case and use this code( You should keep in mind that the fields are built with the class properties according to the Json output):

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>>();

The actual response appears to be of no concern so using a dynamic simplifies things. Converting back to strongly typed objects by calling ToObject was a good choice and should work out fine.

Wow, if you can request the API to respond with json or xml you can make short work of this - but if it really is just tabular text then life becomes a bit more complicated as you need to manually parse the data and convert it into objects.

Let's consider an example object that you might target, containing a collection of another custom type. (Have used list for convenience as we may not know the length of the expected data, you can substitute this for a HashSet if preferred, or even swap things around a bit make this a private collection with a public method that returns it as an array if array is what you need to make use of etc. Also you can change the member types as needed).

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

Here is the nested object.

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

Here is some shortened sample data.

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

Now to parse the sample data with Regex.... Disclaimer - code for example only and contains minimal checking which assumes the data format is consistent. Also my Regex is really basic!

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

Again, just to emphasise, lots of room for improvement here, happy for anyone to make better work of this!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM