I'm very new to c#, so I apologize if this doesn't make any sense!
Using a C# console application, I'm having a hard time parsing a detailed json response and assigning json values to variables. I thought I had everything working by deserializing the json to a string until about 200 iterations in (I'll be geocoding over a million addresses), I received a response with an empty result array that crashed my application. Now I'm trying a new approach using JObject, JProperty, and JToken, but not having much luck.
My json example is is follows ..
{
"input": {
"address_components": {
"number": "123",
"predirectional": "E",
"street": "Main",
"suffix": "St",
"formatted_street": "E Main St",
"city": "Mesa",
"state": "AZ",
"zip": "85209",
"country": "US"
},
"formatted_address": "123 E Main St, Mesa, AZ 85209"
},
"results": [
{
"address_components": {
"number": "123",
"predirectional": "E",
"street": "Main",
"suffix": "St",
"formatted_street": "E Main Ave",
"city": "Mesa",
"county": "Maricopa County",
"state": "AZ",
"zip": "85209",
"country": "US"
},
"formatted_address": "123 E Main St, Mesa, AZ 85209",
"location": {
"lat": 33.123456,
"lng": -111.123456
},
"accuracy": 1,
"accuracy_type": "range_interpolation",
"source": "TIGER\/Line\u00ae dataset from the US Census Bureau",
"fields": {
"congressional_district": {
"name": "Congressional District 5",
"district_number": 5,
"congress_number": "114th",
"congress_years": "2015-2017"
},
"state_legislative_districts": {
"senate": {
"name": "State Senate District 16",
"district_number": "16"
},
"house": {
"name": "State House District 16",
"district_number": "16"
}
},
"school_districts": {
"unified": {
"name": "Gilbert Unified District",
"lea_code": "0403400",
"grade_low": "PK",
"grade_high": "12"
}
},
"timezone": {
"name": "MST",
"utc_offset": -7,
"observes_dst": false
}
}
},
{
"address_components": {
"number": "123",
"predirectional": "E",
"street": "Main",
"suffix": "St",
"formatted_street": "E Main St",
"city": "Mesa",
"county": "Maricopa County",
"state": "AZ",
"zip": "85209",
"country": "US"
},
"formatted_address": "123 E Main St, Mesa, AZ 85209",
"location": {
"lat": 33.123456,
"lng": -111.123456
},
"accuracy": 0.8,
"accuracy_type": "range_interpolation",
"source": "TIGER\/Line\u00ae dataset from the US Census Bureau",
"fields": {
"congressional_district": {
"name": "Congressional District 5",
"district_number": 5,
"congress_number": "114th",
"congress_years": "2015-2017"
},
"state_legislative_districts": {
"senate": {
"name": "State Senate District 16",
"district_number": "16"
},
"house": {
"name": "State House District 16",
"district_number": "16"
}
},
"school_districts": {
"unified": {
"name": "Gilbert Unified District",
"lea_code": "0403400",
"grade_low": "PK",
"grade_high": "12"
}
},
"timezone": {
"name": "MST",
"utc_offset": -7,
"observes_dst": false
}
}
}
]
}
The json that broke my original code ..
{
"input": {
"address_components": {
"number": "123",
"predirectional": "E",
"street": "Main",
"suffix": "St",
"formatted_street": "E Main St",
"city": "Mesa",
"state": "AZ",
"zip": "85209",
"country": "US"
},
"formatted_address": "123 E Main St, Mesa, AZ 85209"
},
"results": []
}
The original code ..
Uri uri = new Uri("https://api.geocod.io/v1/geocode?q=" + geocodioAddress + "&fields=cd,stateleg,school,timezone&api_key=" + app_key);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Method = WebRequestMethods.Http.Get;
request.Accept = "application/json";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string output = reader.ReadToEnd();
response.Close();
dynamic array = JsonConvert.DeserializeObject(output);
if (array.results[0] != null)
{
// cont.
}
The error msg was "Index was out of range. Must be non-negative and less than the size of the collection." The error occurs at "if (array.results[0] != null)".
Now I'm sure this isn't the best approach anyways, so I thought I'd try something new (found here: C# Parsing JSON array of objects) ..
Uri uri = new Uri("https://api.geocod.io/v1/geocode?q=" + geocodioAddress + "&fields=cd,stateleg,school,timezone&api_key=" + app_key);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Method = WebRequestMethods.Http.Get;
request.Accept = "application/json";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string json = reader.ReadToEnd();
response.Close();
var resultObjects = AllChildren(JObject.Parse(json))
.First(c => c.Type == JTokenType.Array && c.Path.Contains("results"))
.Children<JObject>();
foreach (JObject result in resultObjects)
{
foreach (JProperty property in result.Properties())
{
JToken _county = property.Value.SelectToken("county");
string county = Convert.ToString(_county);
// cont.
}
}
This looked really promising, except for three things..
I don't want to parse results[1]. You'll notice in the json response, that the second results instance has a lower accuracy score. And when I don't change the lat/lng values to hide my personal address, these two instances are different with the 2nd being much less accurate.
While I successfully got the value for the county above, I can't get a response for "formatted_address", as well as the value resets each time through the foreach loop.
In the "fields" section, there are multiple objects with the same name. For example..
JToken _county = property.Value.SelectToken("name");
How do I select which "name" I'm looking for? school district, timezone, congressional district, etc..
Again, I'm sorry for such a long post. I've been working on this all week, and just when I thought I had it figured out, one stupid address has to return no results and break everything!! I really appreciate the help of people much smarter than me ... the downside of working from home, no other brains to pick :)