This simple tutorial is about adding MS Excel Add-in and getting the geocodes, i.e., Location Points (Latitude, Longitude) or to verify the accuracy of address, using three Service Providers -
- Bing Maps API.
- Google GeoCode API.
- SmartyStreets LiveAddress API.
This simple solution helps you get rid of jumping around different interfaces to do the same job. More importantly, it does it in batches. So just by one click of a button right inside MS Excel where all the addresses (no matter structured or unstructured) are mentioned, we can have geocodes (Latitude, Longitude) also using APIs.
BackgroundAny developer having experience on .NET platform should be able to grasp this article quickly. Before you jump into the code, make sure you have good knowledge of C# language. And before you could actually achieve the geocodes from the above mentioned geocoding service providers, you need to sign up and get personal API keys to access them. The thing you need other than Visual Studio is:
1. VSTO (Visual Studio Tools for Office) for getting started
Using the codeI will try to be brief and won't be touching any technical details of API itself, as I am covering three different Service Providers for getting GeoCodes. I will provide links to API documentation so that you can read them and implement the same based on your business needs. Let's get started with code.
Step 1: Get the API keys.
For Microsoft Bing Maps API, you need an Azure account. Start free with ₹13,300 in credit to use on any Azure products for 30 days, which is a good deal if you want to learn Azure platform and implement the real world examples. Once you create Azure account and lands on the portal dashboard, you need to search for Bing Maps API by typing in the search box. The suggested link should land you on Bing Maps API for the enterprise. Create new API and navigate to key management and copy the primary key.
Bing Maps API itself is a very vast library to explore, the part we are going to touch is Geocode Dataflow API and its documentation link is here.
For Google Maps GeoCoding API, you need to sign up for Google developer's account. Sign up and getting it is easier with Google developer's account. Just follow this link and get the API key. The same link can be used for documentation as well.
For SmartyStreets LiveAddress API, you need to sign up for a SmartyStreets account and once you do that and land on the Account page, you should see API keys link on the left-hand side and one API key should already be there to use. Remember! SmartyStreets provides free API for US addresses only and that too is 250 per request/month, though you always get the option to upgrade. These guys are pretty much dealing with address-related services so they provide a lot more than what other two providers do in this area. They have a web interface for validating the list of addresses, which do come handy sometimes for business guys and not for developers.
Step 2: Get into Visual Studio
First, let's just add a simple class to get and set the Latitude and Longitude values across all service providers in a similar fashion. All API's return different responses, but we want to make it generic output.
Add class LatitudeLongitude.
- public class LatitudeLongitude {
- public int Id {
- get;
- set;
- }
- public string Latitude {
- get;
- set;
- }
- public string Longitude {
- get;
- set;
- }
- }
For our simplicity, and to provide the configurability to the business user so that they can choose what API they want to go with, we are going to add a configuration file i.e. App.Config. Here I am going to provide total 5 configurable settings,
- GeoLocationService: The service which user want to choose, as of now, only three options can be entered, Microsoft, Google, LiveAddress
- BingMapsAPIKey: The key you got from Bing Maps for Enterprise on azure portal.
- GoogleGeoCodingAPIKey: the key you got from Google developer's guide.
- SmartyStreetsAPIKey: The AuthCode you got from SmartyStreets dashboard.
- SmartyStreetsAuthToken: The authorization token you got from SmartyStreets dashboard.
Here's how your config file should look like.
Now, add a button control by dragging it from Toolbox and name it generateBtn.
Now, add a click event to this button either by double clicking on button or by going from Properties window of button control.
Step 3: Add Services
Let's just first build the logic to consume the API's for which we generated API from service providers and then we will come back to click event of button.
Consuming Google Maps Geocode API
To do that, create Services folder and first add class named GoogleAPI
Then Add GetGoogleAPILocations method that take following parameters,
- addressList
- outputList
Since Google does not provide batch geocoding API, we have to loop over all the addresses that we built in AddressList and we will read the responses one by one and keep adding the same in outputList. Google geocoding API URL:
https://maps.googleapis.com/maps/api/geocode/xml?key=<your API key>&address=<address you want to geocode>&sensor=false
- public static List < LatitudeLongitudeClass > GetGoogleAPILocations(List < string > AdressList, List < LatitudeLongitudeClass > outputList) {
- var key = ConfigurationManager.AppSettings["GoogleGeoCodingAPIKey"];
- string requestUri;
- foreach(var item in AdressList) {
- requestUri = string.Format("https://maps.googleapis.com/maps/api/geocode/xml?key= {
- 0
- } & address = {
- 1
- } & sensor = false ", key, Uri.EscapeDataString(item));
- WebRequest request = WebRequest.Create(requestUri); WebResponse response = request.GetResponse(); XDocument xdoc = XDocument.Load(response.GetResponseStream()); XElement result = xdoc.Element("GeocodeResponse").Element("result"); XElement locationElement = result.Element("geometry").Element("location");
- var lat = locationElement.Element("lat").Value.ToString();
- var lng = locationElement.Element("lng").Value.ToString(); outputList.Add(new LatitudeLongitudeClass {
- Latitude = lat, Longitude = lng
- });
- }
- return outputList;
- }
If you follow the XML response in Google Maps API documentation, you will see our point of concern is in following XPATH. GeocodeResponse>result>geometry>location>lat and GeocodeResponse>result>geometry>location>lng so above code is doing exactly that and adding the same in our list of LatitudeLongitude class.
Now following similar approach let's add Bing Maps API.
Consuming Bing Maps API
Beauty of the Bing Maps API is that it provides many micro services, and based on your requirement, you get to choose what you actually need. Here, we have two options. Either we can choose -
http://dev.virtualearth.net/REST/v1/Locations?q= http://spatial.virtualearth.net/REST/v1/dataflows/geocode - this one provides batch geocoding. Let's add a method for consuming dev.virtualearth.net API.
Add a method named GetBingGeoLocations with the following parameters.
- addressList
- outputList
So, just like what we did for Google API, we follow the same logic, but here is something tricky. Microsoft Bing Maps API service provides DataContracts that helps us to read the response in object manner. So here, we need extra reference of BingMapsRESTToolkit which you can get from NuGet Package Manager, once you do that, your Response object should be accessible.
- using BingMapsRESTToolkit;
- public static List < LatitudeLongitudeClass > GetBingGeoLocations(List < string > AdressList, List < LatitudeLongitudeClass > outputList) {
- string response;
- foreach(var item in AdressList) {
- string requestUri = "http://dev.virtualearth.net/REST/v1/Locations?q=" + Uri.EscapeDataString(item) + "&key=AmQIF1IE_78hrjIdOBG3nxHiz6SMATgQUCVeGtDDgQdC3CzFSIWYlMtO9o-cbBdu";
- using(var client = new WebClient()) {
- response = client.DownloadString(requestUri);
- }
- DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Response));
- Response mapResponse;
- using(var es = new MemoryStream(Encoding.Unicode.GetBytes(response))) {
- mapResponse = (ser.ReadObject(es) as Response); //Response is one of the Bing Maps DataContracts
- }
- Location location = (Location) mapResponse.ResourceSets.First().Resources.First();
- outputList.Add(new LatitudeLongitudeClass {
- Latitude = location.Point.Coordinates[0].ToString(),
- Longitude = location.Point.Coordinates[1].ToString()
- });
- }
- return outputList;
- }

Join the conversation! Your thoughts help the community grow.