Click here to Skip to main content
Click here to Skip to main content

A .NET API for the Google Maps Geocoder

By , 26 Jun 2008
 

Introduction

Google maps allows you to geocode addresses through their JavaScript API or by directly calling http://maps.google.com/maps/geo?output=xml&key=yourkey&q=someaddress for results in XML. Both of these methods can take time to integrate into your .NET code. To make life a little simpler, I've wrapped the functionality of the HTTP geocode request into a .NET library.

Using the Code

You can make a call to only get all XML in a single string:

string xml = GMapGeocoder.Util.GetXml("123 fake street", "your google map key");

You can also get the code back in the original object structure:

string xml = GMapGeocoder.Util.GetXml("123 fake street", "your google map key");
GMapGeocoder.Generated.kml kml = GMapGeocoder.Util.DeserializeXml(xml);
string fullAddress = kml.Response.Placemark[0].address;
string countryCode = kml.Response.Placemark[0].AddressDetails.Country.CountryNameCode;
string stateCode = kml.Response.Placemark[0].AddressDetails.Country.
                AdministrativeArea.AdministrativeAreaName;

For US addresses, the following calls should make more sense than the kml object above:

GMapGeocoder.Containers.Results results = 
    GMapGeocoder.Util.Geocode("123 fake street", "your google map key");
GMapGeocoder.Containers.USAddress match1 = results.Addresses[0];
string city = match1.City;
string state = match1.StateCode;
double lat = match1.Coordinates.Latitude;

Points of Interest

I didn't find an exact XML definition, so I wrote the XSD file based on documentation on Google, along with results I found from making random queries. I included the XSD file just in case this definition is wrong and code needs to be regenerated. I've also noticed that HttpWebRequest.GetResponse() used by the GetXml call is slow on the initial call from an application, but subsequent calls are much quicker.

History

  • 27th May, 2008: Initial post
  • 24th June, 2008: Article updated

License

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

About the Author

Sharmil Y Desai
Software Developer (Senior) Cerner
United States United States
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionImprovement to PlacemarkPointToPointmemberGregg Lobdell6-Jul-11 12:45 
A small efficiency improvement to the Util method PlacemarkPointToPoint. Use a static for the character to split on array, and only do the split once, instead of three times.
 
Also remove the inner try block and replace it with a boolean expression to set p.Unbounded. Since this uses Regex to match zero, I suppose you could also use Regex.Split instead of String.Split.
 
Add to the file header:
using System.Text.RegularExpressions;
 
Then the changes to the code:
        /// <summary>
        /// char array used as first argument to Split
        /// </summary>
        private static char[] splitChar = { ',' };
 
        /// <summary>
        /// regex to match for zero
        /// </summary>
        private static Regex zero = new Regex(@" *0+ *");
 
        /// <summary>
        /// Takes point from google containing coordinates in a string and returns point objects with lat/lng separated out.
        /// </summary>
        /// <param name="point">Google placemark point.</param>
        /// <returns>Point containing coordinates. Lat/Lng are set to min double value on parse errors.</returns>
        public static Containers.Point PlacemarkPointToPoint(Generated.Point point)
        {
            try
            {
                Containers.Point p = new GMapGeocoder.Containers.Point();
                string[] coords = point.coordinates.Split(splitChar);
                p.Longitude = Convert.ToDouble(coords[0]);
                p.Latitude = Convert.ToDouble(coords[1]);
                p.Unbounded = (coords.Length > 2 && !zero.IsMatch(coords[2]));
 
                return p;
            }
            catch
            {
                return new Containers.Point();
            }
        }
 
If you don't like the Regex match for zero you could use:
 
                int unbound = 0;
                p.Unbounded = (coords.Length > 2 
                               && Int32.TryParse(coords[2], out unbound) 
                               && unbound != 0);
 
 
I like TryParse better because it doesn't throw an error. I view Try/Throw/Catch as a relatively expensive operation, better reserved for truly exceptional situations.
 
Enjoy!
QuestionUpdate to Google Geocoding V3?memberGregg Lobdell6-Jul-11 8:37 
Is there a plan to upgrade this to the new API, Geocoding V3?
AnswerRe: Update to Google Geocoding V3?memberMember 831154912-Oct-11 20:07 
http://stackoverflow.com/questions/4824348/working-with-the-google-location-api
GeneralOnly using aspx.vbmemberPaul M Gough26-Nov-09 22:06 
I wanted to see if it was possible to do a functional maps application in aspx.vb code behind without using any javascript. I used your geocoder along with the free Subgurim.Controles activex.
If it would help anyone here is the sample application.
 
Click here for source code.
 
Thank you Sharmil. Great work.
GeneralKML Schemamemberteggen26-Oct-09 17:13 
You can find the complete and official XML (KML) reference including a link to the xsd here:
http://code.google.com/intl/de-DE/apis/kml/documentation/kmlreference.html[^]
 
The complete XML schema for KML is located at http://schemas.opengis.net/kml/[^]
GeneralI need complete seach resultsmembersandeepsc12-Sep-09 2:19 
I need complete seach results from Google Map.when I insert any seach text in google map it only shows me 2 to 3 results.I want information like Name,Address,City,State etc.Which display on the left side to the map.I have a code which gives the data but not which display at google map.I want the solution on this how I get the complete kml file.I have used the same code which you have given
Generalstatus 602memberoksanai25-Jun-09 4:33 
Hi Sharmil,
 
Do you know the way around the status 602.
I mean if you received that status - the exact location wasn't found.
Can I query goggle for the closest location instead?
If I look for the same address using http://maps.google.com/ - it shows me couple of close locations, but API returns status 602 and no location result.
If you know what can be done – please help me.
 
Thank you in advance....
GeneralProblem with culture/ Utf8memberrouliowiglesias24-Jun-09 16:07 
Hi,
 
I had some trouble with the culture and UTF-8 encoding.
I advise you to change:
 
--------------
public static Containers.Point PlacemarkPointToPoint(Generated.Point point)
...
// Parse result independently of the culture
p.Longitude = Double.Parse(point.coordinates.Split(new char[] { ',' })[0], CultureInfo.InvariantCulture.NumberFormat);
p.Latitude = Double.Parse(point.coordinates.Split(new char[] { ',' })[1], CultureInfo.InvariantCulture.NumberFormat);
 
--------------
 
public static string GetXml(string address, string key)
{
//Add utf8 argument
string url = string.Format("http://maps.google.com/maps/geo?output=xml&q={0}&key={1}&oe=utf8", HttpUtility.UrlEncode(address), key);
 
-------------
public static string GetXml(string address, string key)
{
...
//Add Utf8
using (StreamReader readStream = new StreamReader(stream, Encoding.UTF8))
{
return readStream.ReadToEnd();
}
-----------
 
It's run correctly on some manuel test. I will try your code on a big test case Smile | :)
Thank you for your code and the time saving. Smile | :)
Generalweb project problemmemberzerointeractive8-Jun-09 12:29 
Hi Sharmil,
I'm proudly using your GMapGeocoder in a website that I recently developed, but unfortunately when I move to production I receive the following error:

System.Security.SecurityException: Request for the permission of type 'System.Net.WebPermission, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.
at System.Security.CodeAccessSecurityEngine.Check(Object demand, StackCrawlMark& stackMark, Boolean isPermSet)
at System.Security.CodeAccessPermission.Demand()
at System.Net.HttpWebRequest..ctor(Uri uri, ServicePoint servicePoint)
at System.Net.HttpRequestCreator.Create(Uri Uri)
at System.Net.WebRequest.Create(Uri requestUri, Boolean useUriBase)
at System.Net.WebRequest.Create(String requestUriString)
at GMapGeocoder.Util.GetXml(String address, String key)
at html_aspx_index.Page_Load(Object sender, EventArgs e) in \\wagner\wwwroot$\ mysite.ws\index.aspx.cs:line 34
The action that failed was:
Demand
The type of the first permission that failed was:
System.Net.WebPermission
The Zone of the assembly that failed was:
Internet

 
It seems to me to be related to permissions to be set in the web.config: can you help me ? OMG | :OMG:
I dunno how to do it nor where to place any directive to allow your .dll safely contact maps.google.com .Confused | :confused:
 
Any help will be deeply appreciated!
 
Thank you in advance,
 
Luigi
GeneralVery nice :o)memberCipB28-May-09 4:53 
Very nice and structured piece of code. Congrats.
 
Also, It helped me a lot as I was late with a project.
GeneralRe: Very nice :o)memberjonranes28-May-09 7:56 
Yes, this is saving me some days also. Thanks again.
GeneralNice Articlemembermbaocha6-May-09 11:31 
It was a nice article. But Google Map is not very useful in West Africa since it does not detail Nigeria, Ghana and a good number of other west African Country. Could it be possible to get these to work in Some Maps other than Google Map?
 

 

_________________________________________________________
Digital Map Nigeria | Street Level Map of Lagos Abuja Nigeria | GIS company in Nigeria
GeneralMultiple AddressesmemberBlitzPackage27-Aug-08 9:01 
How do I use it for multiple addresses? I have 20,000 addresses to geocode and thus far, using the example you provided, I can't get it to work for more than one address.
 
Thanks in advance. Also, I think the code is great overall.
 
This is my code:
 
private void GoogleGeoCode()
{
ExcelFile ef = new ExcelFile();
 
ef.LoadXls(@"C:\Documents and Settings\Addreses08270801.xls");
 
ExcelWorksheet ws = ef.Worksheets["Addresses"];
 
int row = ws.Rows.Count;
int addressesLeft = row - 1;
string addressLocation;
string latitudeLocation;
string longitudeLocation;
 
GMapGeocoder.Containers.Results results;
 
GMapGeocoder.Containers.USAddress match1; // = results.Addresses[0];
 
double lat; // = match1.Coordinates.Latitude;
double longt; // = match1.Coordinates.Longitude;
 
for (int record = 2; record < (row + 1); record++)
{
AddressesLeft.Content = "Working On Address: " + addressesLeft.ToString();
 
addressLocation = "E" + record.ToString();

results = GMapGeocoder.Util.Geocode(ws.Cells[addressLocation].Value.ToString(), myGeocodeKey);
 
match1 = results.Addresses[0];
 
lat = match1.Coordinates.Latitude;
longt = match1.Coordinates.Longitude;
 
latitudeLocation = "K" + record.ToString();
longitudeLocation = "L" + record.ToString();
 
ws.Cells[latitudeLocation].Value = lat;
ws.Cells[longitudeLocation].Value = longt;
 
addressesLeft--;
}
 
AddressesLeft.Content = "Saving File....";
 
ef.SaveXls(@"C:\Documents and Settings\Addreses08270803.xls");
 
AddressesLeft.Content = "Finished!";
}
GeneralRe: Multiple AddressesmemberSharmil Y Desai13-Sep-08 5:29 
That looks like it should work. You might try setting a break point after the GMapGeocoder.Util.Geocode call, and looking at the results after each iteration of the loop. Might be an issue with your results not getting saved out. Not sure if it makes a difference but you might also create variables referenced only by the loop inside the loop.
 
So instead of:
addressLocation = "E" + record.ToString();
Use:
string addressLocation = "E" + record.ToString();
I'd do this for results, match1, lat, longt, latitudeLocation, and longitudeLocation. Also I'd be cautious geocoding a list of addresses with google maps since I think it violates there usage terms.
GeneralUK address supportmembergeedubb27-Aug-08 1:08 
Hi
 
Useful article - it would be nice to see some UK address support added though.
 
Thanks
GeneralConnection refusedmemberLars Karlsson3-Jul-08 21:37 
I get this error when I use your component.
It works just fine locally, but when I move I get this error.
"
[SocketException (0x274d): No connection could be made because the target machine actively refused it]"
 

[SocketException (0x274d): No connection could be made because the target machine actively refused it]
System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress) +1001890
System.Net.Sockets.Socket.InternalConnect(EndPoint remoteEP) +33
System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure, Socket s4, Socket s6, Socket& socket, IPAddress& address, ConnectSocketState state, IAsyncResult asyncResult, Int32 timeout, Exception& exception) +431
 
[WebException: Unable to connect to the remote server]
System.Net.HttpWebRequest.GetResponse() +1501755
GMapGeocoder.Util.GetXml(String address, String key) in C:\Development\Lafarge Roofing\GMapGeocoder\Util.cs:39
SYSteamCAB.Custom.RoofConfigurator.Web._Default.Page_Load(Object sender, EventArgs e) in C:\Development\Lafarge Roofing\Roof Configurator\SYSteamCAB.Custom.RoofConfigurator.Web\Clientdata.aspx.cs:645
System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +15
System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +34
System.Web.UI.Control.OnLoad(EventArgs e) +99
System.Web.UI.Control.LoadRecursive() +47
System.Web.UI.
GeneralRe: Connection refusedmemberSharmil Y Desai7-Jul-08 16:31 
I would check if there are firewall rules on the box that you are deploying, which are blocking access to maps.google.com over port 80. If you can remote to the box I'd open a command window and run "telnet maps.google.com 80". Should go to a blank screen if there are no problems. You could also try calling http://maps.google.com/maps/geo?output=xml&key=yourkey&q=someaddress directly from a browser window on that box.
 
- Sharmil
GeneralRe: Connection refusedmemberSharmil Y Desai7-Jul-08 16:39 
Also I'd make sure you're not using a proxy on the deployment box. I think you can add lines to your web.config if you need to specify proxy settings for .Net to use.
GeneralOne morememberwjcygan20-Jun-08 6:29 
The coordinates returned by Google have the longitude first, then the latitude in the node. Your code switched that around.
 
You need the following change:
 
    /// <summary>
    /// Takes point from google containing coordinates in a string and returns point objects with lat/lng separated out.
    /// </summary>
    /// <param name="point">Google placemark point.</param>
    /// <returns>Point containing coordinates. Lat/Lng are set to min double value on parse errors.</returns>
    public static Containers.Point PlacemarkPointToPoint(Generated.Point point)
    {
        try
        {
            Containers.Point p = new GMapGeocoder.Containers.Point();
            p.Longitude = Convert.ToDouble(point.coordinates.Split(new char[] { ',' })[0]);
            p.Latitude = Convert.ToDouble(point.coordinates.Split(new char[] { ',' })[1]);
 
            // Don't return empty point if we fail here.
            try
            {
                p.Unbounded = Convert.ToBoolean(Convert.ToInt32(point.coordinates.Split(new char[] { ',' })[2]));
            }
            catch { }
 
            return p;
        }
        catch
        {
            return new Containers.Point();
        }
    }
This just switches the Longitude and Latitude.
 
Walt

GeneralRe: One morememberSharmil Y Desai24-Jun-08 7:41 
Should be fixed now. I noticed this too when I started using the code and had addresses in the ocean. haha. Forgot to update the code here though.
GeneralSlight changememberwjcygan20-Jun-08 4:39 
You might want to make the following change to your code in Util.cs:
 
        /// <summary>
        /// Takes google objects and returns US friendly query results.
        /// </summary>
        /// <param name="kml">Deserialize xml objects from google.</param>
        /// <returns></returns>
        public static Containers.Results GoogleObjectsToResults(Generated.kml kml)
        {
            Containers.Results results = new GMapGeocoder.Containers.Results();
            results.StatusCode = (StatusCodeOptions)kml.Response.Status.code;
            results.Query = kml.Response.name;
 
            if (kml.Response.Placemark != null)
            {
                foreach (Generated.Placemark p in kml.Response.Placemark)
                {
                    results.Addresses.Add(PlacemarkToUSAddress(p));
                }
            }
            return results;
        }
 
This just checks to see if Placemark is not null before using it.
 
Nice article. It was very helpful.
 
Walt
GeneralRe: Slight changememberSharmil Y Desai24-Jun-08 7:38 
Thanks, didn't catch this. Should be updated on here now.
GeneralErrormemberobinna_eke29-May-08 1:24 
Do you know why I am getting this error? I have my Google key as well
 

Server Error in '/SeeAjax' Application.
The remote name could not be resolved: 'maps.google.com'
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
 
Exception Details: System.Net.WebException: The remote name could not be resolved: 'maps.google.com'
 
Source Error:
 
Line 15: protected void Page_Load(object sender, EventArgs e)
Line 16: {
Line 17: string xml = GMapGeocoder.Util.GetXml("35 Greville Court Napoleon Road London E5 8TF", "ABQIAAAA_LYa_-GfNtQyBdJspQIboBRa7FnI_mqQJH5Raddl725svEZDkRSDjPurwcgJXErd6JKjFzLWFUbDGg");
Line 18: Response.Write(xml);
Line 19: }
 

Source File: c:\Inetpub\wwwroot\customers\SeeAjax\Geocode.aspx.cs Line: 17
 
Stack Trace:
 
[WebException: The remote name could not be resolved: 'maps.google.com']
System.Net.HttpWebRequest.GetResponse() +1502043
GMapGeocoder.Util.GetXml(String address, String key) +134
Geocode.Page_Load(Object sender, EventArgs e) in c:\Inetpub\wwwroot\customers\SeeAjax\Geocode.aspx.cs:17
System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +15
System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +34
System.Web.UI.Control.OnLoad(EventArgs e) +99
System.Web.UI.Control.LoadRecursive() +47
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1061
 

Version Information: Microsoft .NET Framework Version:2.0.50727.42; ASP.NET Version:2.0.50727.42
GeneralRe: ErrormemberSharmil Y Desai29-May-08 10:55 
That's an odd error, seems more like a DNS issues where the box this is running on can't find maps.google.com . Can you get to http://maps.google.com/maps/geo?q=1600+Amphitheatre+Parkway,+Mountain+View,+CA&output=xml&key=ABQIAAAA_LYa_-GfNtQyBdJspQIboBRa7FnI_mqQJH5Raddl725svEZDkRSDjPurwcgJXErd6JKjFzLWFUbDGg directly from your browser on the box running the application?
 
Tried your exact call on my machine with the library and it seems to be working fine even though google can't resolve that address.
 
I get a 602 response back:
 
<?xml version="1.0" encoding="UTF-8"?><kml xmlns="http://earth.google.com/kml/2.0"><Response><name>35 Greville Court Napoleon Road London E5 8TF</name><Status><code>602</code><request>geocode</request></Status></Response></kml>

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

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130617.1 | Last Updated 26 Jun 2008
Article Copyright 2008 by Sharmil Y Desai
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid