Click here to Skip to main content
15,881,803 members
Articles / Programming Languages / C#
Tip/Trick

Google Geocoding and Reverse Geocoding

Rate me:
Please Sign up or sign in to vote.
4.67/5 (3 votes)
1 May 2013CPOL3 min read 41.4K   1.4K   9   7
A class library to manage the JSON interface to the Google Geocoding API

Introduction

I recently had a project for a client to take in positional records from a tracking unit and reverse geocode the result to a street to make the data useful. Whilest doing this project, I came up with a nice static class to take the complexity out of the task in hand.

The Google API for reverse geocoding (https://developers.google.com/maps/documentation/geocoding/) is a RESTful JSON service. In this project I have abstracted away the JSON response and serialised them into useful objects to use hiding away the complexity of the data to the developer.

Using the code

A test project is include in the project attached to this article.

The Google Reverse Geocoder is a seal static class so you not have and cannot create an instance of this object to use it. You simply call the static members of the class.

If you are a Google Premier customer, Google will supply you with a Client ID and a Secret Key to sign the requests to Google with. To enter these values, simply call the following code:

C++
GoogleReverseGeocoder.ClientId = yourClientId;
GoogleReverseGeocoder.SecretKey = yourSecretKey;

If you are using the free limited use version, simply ommit these lines and the class will not pass anything to Google. Once these are set, they no not require setting again as the class is static.

To perform a reverse geocode call one of the following:

C#
string result = GoogleReverseGeocoder.ReverseGeocode(lat, lng, out success);

Or

C#
GoogleGeoCodeResponse result = 
         GoogleReverseGeocoder.ReverseGeocodeGetWholeResponse(lat, lng, out success);

The first call returns the closest result as a well formatted string. The second call returns the whole result from Google so you can get more information if needed.

Under the hood both call the following:

C#
public static GoogleGeoCodeResponse ReverseGeocodeGetWholeResponse(
            double latitude, double longitude, string secretKey)
{
   string data = new System.Net.WebClient().DownloadString(Sign(
     string.Format(googleWebAddress, latitude, longitude), secretKey));
   byte[] response = Encoding.Unicode.GetBytes(data);
   using (MemoryStream ms = new MemoryStream(response))
   {
      var deserialiser = new DataContractJsonSerializer(typeof(GoogleGeoCodeResponse));

      GoogleGeoCodeResponse result = (GoogleGeoCodeResponse)deserialiser.ReadObject(ms);
      return result;
    }
}

As you can see, the code downloads the string from the Google API using a .NET WebClient. The JSON result of this is then deserialized into a GoogleGeoCodeResponse object. This object is a class defination that matches the JSON objects returned from Google. This removes the need to parse the strings directly.

These classes need to be defined as Data Contracts and have Data Members so match the names in the returned JSON as shown below:

C#
[DataContract]
public class GoogleGeoCodeResponse
{
    [DataMember]
    public string status { get; set; }
    [DataMember]
    public results[] results { get; set; }
}

[DataContract]
public class results
{
    [DataMember]
    public string formatted_address { get; set; }
    [DataMember]
    public geometry geometry { get; set; }
    [DataMember]
    public string[] types { get; set; }
    [DataMember]
    public address_component[] address_components { get; set; }

}
[DataContract]
public class geometry
{
    [DataMember]
    public string location_type { get; set; }
    [DataMember]
    public location location { get; set; }
}
[DataContract]
public class location
{
    [DataMember]
    public string lat { get; set; }
    [DataMember]
    public string lng { get; set; }
}
[DataContract]
public class address_component
{
    [DataMember]
    public string long_name { get; set; }
    [DataMember]
    public string short_name { get; set; }
    [DataMember]
    public string[] types { get; set; }
}

As you can see, the URL needs to be signed if you are a Google Premier customer. Signing is achieved by the following:

C#
private static string Sign(string url, string secretKey) 
{
    if (!string.IsNullOrEmpty(ClientId))
        url += string.Format("&client={0}", ClientId);
    if (!string.IsNullOrEmpty(secretKey))
    {
        string usablePrivateKey = secretKey.Replace("-", "+").Replace("_", "/");
        byte[] privateKeyBytes = Convert.FromBase64String(usablePrivateKey);
        Uri uri = new Uri(url);
        byte[] encodedPathAndQueryBytes = 
          System.Text.ASCIIEncoding.ASCII.GetBytes(uri.LocalPath + uri.Query);
        // compute the hash       
        HMACSHA1 algorithm = new HMACSHA1(privateKeyBytes);
        byte[] hash = algorithm.ComputeHash(encodedPathAndQueryBytes);
        // convert the bytes to string and make url-safe by replacing '+' and '/' characters       
        string signature = Convert.ToBase64String(hash).Replace("+", 
                      "-").Replace("/", "_");
        // Add the signature to the existing URI.       
        return uri.Scheme + "://" + uri.Host + uri.LocalPath + 
                     uri.Query + "&signature=" + signature;
    }
    return url;
}

If the Client ID is set and the Secret Key is set, the Sign method will add the Client ID to the end of the URL and then add use this URL with a HMACSHA1 hashing algorithm with your secret key to produce a signature. This signature is then appended to the URL query string so that it is passed to Google and they can verify your account.

If the Client ID or Secret Key are not set, the method simply returns the orginial URL which will allow you to call the public Google API.

Useful Information

If you do not have a Google Premier account, you are limited to 2500 lookups a day from your IP address at a rate of 2 lookups per second.

With a Google Premier account, these rates are raised to 100,000 lookups a day at a rate of 10 per second.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Business Analyst
United Kingdom United Kingdom
Professional Freelance Business Analyst specialising in embedded devices and communications.

11 years development, design and requirements capture experience with a focus on quality and innovation

Comments and Discussions

 
QuestionThank you. Pin
ARASH_TAJALLI14-Dec-13 17:24
ARASH_TAJALLI14-Dec-13 17:24 
GeneralMy vote of 5 Pin
Michael Rosqvist3-Sep-13 0:29
Michael Rosqvist3-Sep-13 0:29 
QuestionNot working?? Pin
joskoZD21-Sep-12 5:03
joskoZD21-Sep-12 5:03 
QuestionSource code? Pin
Member 89385397-May-12 4:10
Member 89385397-May-12 4:10 
AnswerRe: Source code? Pin
ArnoDavis11-May-12 4:13
ArnoDavis11-May-12 4:13 
GeneralRe: Source code? Pin
Adelino Paulo26-Apr-13 2:19
Adelino Paulo26-Apr-13 2:19 
GeneralRe: Source code? Pin
ArnoDavis1-May-13 8:41
ArnoDavis1-May-13 8:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.