I recently had a requirement for a mapping application that required me to pass in longitude and latitude coordinates. It wasn’t realistic to have the user look those values up, so I had to figure out a way to automatically lookup the coordinates given a zip code.

There are tons of pay services (some of which I use), but for this project needed something free. I stumbled on http://www.geonames.org/ which has a great service. You can see their webservice documentation here: http://www.geonames.org/export/web-services.html.

Ok, let’s get started:

Web form

These are the input fields we will use to perform the lookup. We are going to have three textboxes, one which has an onchange event.

    Zip Code<br/>
    <%= Html.TextBox("Zip", "", new { @onchange = "LookupCoordinates(this.value)" })%>
    <br/><br/>
    Latitude: <%= Html.TextBox("Lat") %>,
    Longitude:<%= Html.TextBox("Lon") %>

jQuery Function

This function is responsible for looking up the latitude and longitude coordinates, and populating the results into the textboxes. Note that I’m wiring in US as the country below. The country is an optional parameter, when entered gives you more relevant results. Otherwise you are going to have to write some kind of loop.

    function LookupCoordinates(zip) {
            $.post("/Home/LookupCoordinates",
            { Zip: zip, Country: "US" },
            function(data) {
                var result = eval('(' + data + ')');
                var coordinates = result.split(",");
                $("#Lat").val(coordinates[0]);
                $("#Lon").val(coordinates[1]);
            });
        }

Call Geonames.org

In this sample, the call to geonames.org is wired into the controller. In real life, you probably want to wrap it in some kind of helper or service class. There are a few using statements you will need:

using System.IO;
using System.Net;
using System.Xml;

The above namespaces are important because we are going to make a WebRequest, and then parse the Xml results. The webservice method we are going to call is:

http://ws.geonames.org/postalCodeSearch?postalcode=78702&amp;maxRows=10&amp;country=US

Since we know the Zip and the Country, we should in theory only get 1 result. Below is a screenshot of the elements returned for our 78702 search (Austin):

Onto the method:

    public ActionResult LookupCoordinates(string Zip, string Country)
    {
        string Lat = "";
        string Lon = "";
        string PostUrl = "http://ws.geonames.org/postalCodeSearch?postalcode=" + Zip + "&maxRows=10&country=" + Country;
        WebResponse webResponse = webRequest.GetResponse();
        if (webResponse == null)
        { }
        else
        {
            StreamReader sr = new StreamReader(webResponse.GetResponseStream());
            string Result = sr.ReadToEnd().Trim();
            if (Result != "")
            {
                // Load the response into an XML doc
                XmlDocument xdoc = new XmlDocument();
                xdoc.LoadXml(Result);
                //  Navigate to latitude node
                XmlNodeList name = xdoc.GetElementsByTagName("lat");
                if (name.Count > 0)
                {
                    Lat = name[0].InnerText;
                }
                //  Navigate to longitude node
                name = xdoc.GetElementsByTagName("lng");
                if (name.Count > 0)
                {
                     Lon = name[0].InnerText;
                }
            }
        }
        return Json(Lat + "," + Lon);
    }

From there, the method returns the latitude and longitude in a comma separated string, the javascript call splits the results and populates each respective text box. Below is a video preview – really short, really lame, but you get to see the code in action: