coolhand
coolhand

Reputation: 2061

Integrating with NOAA API

I am trying to learn how to integrate the NOAA API ( https://www.ncdc.noaa.gov/cdo-web/webservices/v2#gettingStarted)

by using a method similar to that outlined here: https://learn.microsoft.com/en-us/dotnet/csharp/tutorials/console-webapiclient

to deserialize weather data associated with a specific location

I have a Result.cs object

public class Result
{
    public DateTime Date { get; set; }
    public string DataType { get; set; }
    public string Station { get; set; }
    public string Attributes { get; set; }
    public int Value { get; set; }
}

which I try to serialize and write to the console to test:

private static async Task ProcessRespositories()
{
    var serializer = new DataContractJsonSerializer(typeof(List<Result>));
    //token set from https://www.ncdc.noaa.gov/cdo-web/token
    string token = "myToken";
    var client = new HttpClient();
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Add("token", token);
    //url taken from https://www.ncdc.noaa.gov/cdo-web/webservices/v2#data for daily summaries
    string url = "https://www.ncdc.noaa.gov/cdo-web/api/v2/data?datasetid=GHCND&locationid=ZIP:28801&startdate=2010-05-01&enddate=2010-05-01"
    //this is null
    var streamTask = client.GetStreamAsync(url);
    var repositories = serializer.ReadObject(await streamTask) as List<Result>;

    foreach (var repo in repositories)
        Console.WriteLine(repo.Value);
}

the result I get in the stream from that url seems empty. I'm just learning but unsure of my error here.

Upvotes: 2

Views: 1539

Answers (1)

rene
rene

Reputation: 42463

The payload that you get out of that response looks like this:

{"metadata":{"resultset":{"offset":1,"count":8,"limit":25}},"results":[{"date":"2010-05-01T00:00:00","datatype":"PRCP","station":"GHCND:US1NCBC0005","attributes":",,N,","value":0},{"date":"2010-05-01T00:00:00","datatype":"SNOW","station":"GHCND:US1NCBC0005","attributes":",,N,","value":0}]}

The type that you give the DataContractSerializer need to match that payload. You're missing a topcontainer. Also the names of fields are case sensitive. I used an DataMember attribute to adjust for the correct casing. Last but not least, the datetime format is not by default supported. For now I changed that to a string type. You might want to see if https://stackoverflow.com/a/9347678/578411 can work for you or switch to Json.NET

Here are the Model classes

public class Noaa
{
    public MetaData metadata {get;set;}
    public List<Result> results;
}

public class MetaData 
{
    public ResultSet resultset {get;set;}
}

public class ResultSet
{
   public int offset{get;set;}
   public int count{get;set;}
   public int limit{get;set;}
}

[DataContract]
public class Result
{
    [DataMember(Name="date")]
    public string Date { get; set; } // now a string!
    [DataMember(Name="datatype")]
    public string DataType { get; set; }
    [DataMember(Name="station")]
    public string Station { get; set; }
    [DataMember(Name="attributes")]
    public string Attributes { get; set; }
    [DataMember(Name="value")]
    public int Value { get; set; }
}

And your serializer would need to change to use the container type:

var serializer = new DataContractJsonSerializer(typeof(Noaa));

// other code the same

// call the serializer
var repositories = (Noaa) serializer.ReadObject(await streamTask);

// respositories is now a Noaa type, 
// its member results holds your list.
foreach (var repo in repositories.results)
            Console.WriteLine(repo.Value);

If you want to examine the payload instead of handing it to the serializer you can use a StreamReader like so:

var sw= new StreamReader(await streamTask);
Console.WriteLine(sw.ReadToEnd());

use a Chrome plugin Postman or use a webproxy like Fiddler

Upvotes: 3

Related Questions