Search code examples
c#jsonhttpwebrequestyahoojsonserializer

Consuming Yahoo PlaceFinder JSON in C# using WebRequest


I thought I would post this here not so much as a question but to share with the community some code I wrote after not being able to find the answer here on StackOverflow. If someone would like to take a look at the code and improve it, that would be great, but not required. I have left out some code (try-catch blocks & error handling) to make it a little bit easier to consume the concept and code.


Solution

  • So, let's start with the problem I needed to solve. I wanted to be able to allow someone to enter part or all of a city, state, zipcode combination and use Yahoo's PlaceFinder API to figure out exactly where it was. Nothing fancy, just a simple way to resolve a city & state from a zip code or vice-versa.

    This process involves:

    1. Receiving the input (city/state/zip) server-side
    2. Constructing a URL with the proper parameters (I wanted to receive the response in JSON format)
    3. Making the HTTP GET request to the PlaceFinder service.
    4. Consuming the JSON response in a way that would give me an object model in C# to easily work with the reponse data.

    Let's start with the namespaces you'll want to import:

    using System.Net; // for HttpWebRequest
    using System.Text; // for utf8 encoding
    using System.Web.Script.Serialization; // for json parsing
    using System.IO; // for datastream
    

    Next, let's look at constructing the request:

    string parameters = String.Empty;
    UTF8Encoding utf8 = new UTF8Encoding(); // yahoo docs state utf-8 encoding
    string unparsedLocation = "Beverly Hills, CA 90210"; // contrived example
    
    parameters += "line2=" + Url.Encode(unparsedLocation); // yahoo docs say to url encode
    parameters += "&flags=J"; // J = want the response formatted in json
    parameters += "&appid=[your-app-id-here]"; // using your appID obtained from Yahoo
    parameters = utf8.GetString(utf8.GetBytes(parameters));
    WebRequest request = WebRequest.Create(@"http://where.yahooapis.com/geocode?" + parameters);
    request.Method = "GET";
    

    Next, we want to get the response and put it into an object model that makes it easy to work with:

    WebResponse response = request.GetResponse();
    // Check the status. If it's not OK then don't bother with trying to parse the result
    if (((HttpWebResponse)response).StatusCode == HttpStatusCode.OK)
    {
        // Get the stream containing content returned by the server.
        Stream dataStream = response.GetResponseStream();
        // Open the stream using a StreamReader.
        StreamReader reader = new StreamReader(dataStream);
        // Read the content.
        string responseFromServer = reader.ReadToEnd();
    
        JavaScriptSerializer jss = new JavaScriptSerializer();
        YahooResponse yr = jss.Deserialize<YahooResponse>(responseFromServer);
    
        // You may not want such strict checking; if not, remove the "NO ERROR" check
        if (yr.ResultSet.Error == 0 && yr.ResultSet.ErrorMessage.ToUpper() == "NO ERROR" && yr.ResultSet.Found > 0)
        {
            // inside here is where you can do whatever you need to.
            // ex. 1 - get the first result
            Result result = yr.ResultSet.results[0];
    
            // ex. 2 - loop through results
            foreach (Result r in yr.ResultSet.results)
            {
                // add values to a List<T> or something useful
            }
        }
    }
    
    // always do this as a matter of good practice
    response.Close();
    

    But wait, there's one last important piece missing. What is a 'YahooResponse' object? What does the class definition look like? Here is what I came up with:

    namespace PlaceFinder
    {
        public class YahooResponse
        {
            public ResultSet ResultSet { get; set; }
        }
    
        public class ResultSet
        {
            public string version { get; set; }
            public int Error { get; set; }
            public string ErrorMessage { get; set; }
            public string Locale { get; set; }
            public int Quality { get; set; }
            public int Found { get; set; }
            public Result[] results { get; set; }
        }
    
        public class Result
        {
            public int quality { get; set; }
            public string latitude { get; set; }
            public string longitude { get; set; }
            public string offsetlat { get; set; }
            public string offsetlon { get; set; }
            public int radius { get; set; }
            public string name { get; set; }
            public string line1 { get; set; }
            public string line2 { get; set; }
            public string line3 { get; set; }
            public string line4 { get; set; }
            public string house { get; set; }
            public string street { get; set; }
            public string xstreet { get; set; }
            public string unittype { get; set; }
            public string unit { get; set; }
            public string postal { get; set; }
            public string neighborhood { get; set; }
            public string city { get; set; }
            public string county { get; set; }
            public string state { get; set; }
            public string country { get; set; }
            public string countrycode { get; set; }
            public string statecode { get; set; }
            public string countycode { get; set; }
            public string uzip { get; set; }
            public string hash { get; set; }
            public long woeid { get; set; }
            public int woetype { get; set; }
        }
    }
    

    Read more about the PlaceFinder service here: http://developer.yahoo.com/geo/placefinder/guide/