Geocode addresses in .Net using the Google Geocoding API

Ten years ago I had a project that required finding locations within a certain radius of a given coordinate. Back then, the US Postal Service had a database of latitude-longitude coordinates for every zip code in the US. We loaded that monthly into a local database and wrote custom code to perform look-ups.

Recently I had to do the same thing, but the world is a much different place now. A quick web search on Geocoding produces several free web services that provide much better data, real time, and worldwide. I settled on the Google solution given the fact that Google will probably be around for a while, and their data is very reliable. Note that this service does limit you to 2500 queries a day, which is many more than we will need for this application. You can read all about the details of their service here:

http://code.google.com/apis/maps/documentation/geocoding/index.html

Basically, this service uses REST calls accepting a simple address string and returning either XML or JSON. I chose JSON for it’s simplicity, but had to use an open source library for parsing the data (more on this later). Two parameters are required: sensor and address. Address is self-explanatory, but “sensor” tells Google if we are using a hardware location sensor such as from a phone. In this case, we are not, so it is false. For an example of an address look-up, enter the following into your browser and you will see the JSON results returned.

https://maps.googleapis.com/maps/api/geocode/json?sensor=false&address=350+5th Ave,+New+York,+NY+10118

As you will see, a bunch of data is returned. For my purposes all I care about is the Latitude and Longitude, and also the Status just to make sure the data call succeeded. So I created a custom class in my project to retain this information.


public class GeoData
{
   public string Status { get; set; }
   public double Latitude { get; set; }
   public double Longitude { get; set; }
}

So how do we execute this service call from .Net and parse the results into the GeoData container?

Unit Tests

In the spirit of TDD, I first created these unit tests to confirm the service is returning correct data:


[TestMethod()]
public void GeocodeAddress_Returns_Success()
{
   // Arrange
   const string address = "350 5th Ave, New York, NY 10118";

   // Act
   var result = GeoService.GeocodeAddress(address);

   // Assert
   Assert.AreEqual("OK", result.Status);
}

[TestMethod()]
public void GeocodeAddress_Returns_Correct_Location()
{
   // Arrange
   const string address = "350 5th Ave, New York, NY 10118";

   // Act
   var result = GeoService.GeocodeAddress(address);

   // Assert
   Assert.AreEqual(40.74807, result.Latitude);
   Assert.AreEqual(-73.984959, result.Longitude);
}

Parsing JSON

Executing the call to the service returns JSON, which is basically just a string of data formatted specifically for JavaScript. Since I needed to get the data into a .NET structure, I chose to use the excellent JsonFx open source component (which is installable through Visual Studio using the Nuget package manager) for this task. The JsonFx code and documentation can be found here:

http://github.com/jsonfx/jsonfx

The feature of this library that I used converts the JSON result string into a .Net 4.0 dynamic object that can then be used to extract just the data elements that I care about.

The Code

I created a class in my project library to encapsulate the Google service call. This is typically a good practice, and results in the benefit of allowing us to swap out the provider, say from Google to Bing, without breaking any of the consuming code.


using JsonFx.Json;

namespace Project.Services
{
   public static class GeoService
   {
      public static GeoData GeocodeAddress(string address)
      {
         const string geoService = "<a href="https://maps.googleapis.com/maps/api/geocode/json?sensor=false&address=%22;">https://maps.googleapis.com/maps/api/geocode/json?sensor=false&address=";</a>

         // retrive the json geo data
         var encodedAddress = HttpUtility.UrlEncode(address);
         var jsonResult = new WebClient().DownloadString(geoService + encodedAddress);

         // convert the json result data to an object
         var reader = new JsonReader();
         dynamic jsonObject = reader.Read(jsonResult);

         // populate our typed object from the dynamic one.
         var geoData = new GeoData();
         geoData.Status = jsonObject.status;
         geoData.Latitude = jsonObject.results[0].geometry.location.lat;
         geoData.Longitude = jsonObject.results[0].geometry.location.lng;

         return geoData;
      }
   }
}

The code should be pretty easy to follow. It does the following:

  1. URL Encodes the address string so that spaces are replaced with “+” characters, etc., so it will work as part of a URL
  2. Uses the WebClient object to execute the web service call and retrieve the JSON result as a string.
  3. Uses the JsonFx JsonReader to load the data into a dynamic object
  4. Creates a new GeoData object and maps it’s three properties from the dynamic JSON object

If you combine these pieces and execute the tests, you will see they pass.

That is it.. easy! We can now Geocode any address instantly and for free.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s