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

Force the Photo Screen Saver through Domain Policy

After searching for a way to push out settings to have everyone in the company get a photo screen saver with predefined photos running, I was able to piece out a solution. The steps to enable this are listed below. If there are issues with this or a better way to do a section, please let me know.

Overall, there are three steps to accomplish this. They are:

  1. Create a batch file to copy the photos from a file share to a local folder on the user’s computer, and put this into the logon script of the GPO policy
  2. Set the Administrative Templates to force the correct screen saver to engage
  3. Set the registry keys to direct the screen saver to use the user’s local photo folder

Note: in these examples I have a network file share called “Software” on the fileserver “FS1” that all users have read access to. That contains a folder called “Screen Saver Photos” that is used as the source for the photos. This folder is copied automatically to the user’s C drive when they log on. The reason we just don’t point the screen saver to the share is that we want the screen saver to work when users are disconnected, such as offsite with a laptop.

Step 1: Create a batch file to copy the photos from a file share to a local folder on the user’s computer, and put this into the logon script of the GPO policy

Create a batch file on the domain controller called “ScreenSaverPhotoCopy.bat”. Edit this file and place the following four lines into it. This batch file will run when users log into their machines. These lines map the network drive, make the local folder, purge old files from the folder, and refresh the files from the share, respectively.

net use s: \\fs1\Software
mkdir “C:\Screen Saver Photos”
del /Q “C:\Screen Saver Photos\*.*”
xcopy “S:\Screen Saver Photos” “C:\Screen Saver Photos”

On the domain server, open “Administrative Tools -> Group Policy Management”

Drill into your domain and pick the policy you want to effect, such as “Default Domain Policy”

image

Right click and choose “Edit…”. The Group Policy Management Editor will open.

Open “User Configuration -> Windows Settings -> Scripts (Logon/Logoff)”

image

Double click Logon, this opens Logon Properties

image

You need to move the batch file into a particular store on the server, so click the “Show Files…” button. Copy the “ScreenSaverPhotoCopy.bat” file that you made into this location. Close it.

image

Back on the Logon Properties screen, click “Add…”

Click browse and select the batch file you just copied up.

clip_image006

Click OK and you will see

image

Step 2: Set the Administrative Templates to force the correct screen saver to engage

Back on the Group Policy Management Editor, Expand the “User Configuration –> Policies –> Administrative Templates –> Control Panel” node and click the “Display” item.

image

This lists domain policy settings that affect themes, including screen savers. Enable all the items you want in effect, depending on how strict you want things. In this case, I enabled “Enable Screen Saver”, “Password protect the screen saver”, “Screen saver timeout”, and “Force specific screen saver”. For that last one, set the screen saver to “PhotoScreensaver.scr” as so:

image

Step 3: Set the registry keys to direct the screen saver to use the folder user’s local photo folder

In this step you need to pull the registry settings for the Photo Screen Saver off of a Windows 7 client machine and put them into the domain policy. The Photo Screen Saver uses a particular series of registry keys, and for some reason encrypts the path to the photos folder, so you cannot hand enter this. So the process is, configure the screen saver on a Windows 7 machine, export the registry settings, import them on the domain controller, then add the key path to the policy.

On a Win7 machine, configure the Photo Screen Saver.

Pick “Photos”

image

Click “Settings…”.

image

Browse to the local photo folder, in this case “C:\Screen Saver Photos”. Also set the speed and if you wan them to shuffle.

Run Regedit and drill down into “HKEY_CURRENT_USER\Software\Microsoft\Windows Photo Viewer\Slideshow\Screensaver”. Here you will see three keys, one called EncryptedPIDL which is the encrypted path to the photos folder, one for shuffle, and one for speed.

image

Right click the “Screensaver” folder and choose “Export”. Save the file as “PhotoKeys.reg”.

Copy the file to your domain controller.

Double click the “PhotoKeys.reg” to import them into the domain controller’s registry. You will see a warning like so:

image

If you want you can repeat the registry steps from the Windows 7 machine to confirm the keys were imported properly.

Back in the “Group Policy Management Editor”, drill into “User Configuration –> Preferences –> Windows Settings –> Registry”

image

Right click “Registry” and choose “New –> Registry Wizard”

In the “Registry Browser” window, choose “Local Computer”. Note: I did try to use “Another Computer” to skip the registry import steps above, but was unable to get this to work.

image

Pick the registry key to include, which is the same one we imported above. Check off the four keys that are listed under the “Screensaver” folder.

image

Click Finish. This will create a folder in the policy under Registry, named “Registry Wizard Values”. I don’t think this name matters, but I changed it to “Photo Screen Saver Settings” for clarity. You can also verify the keys are there and have the correct values.

image

Close the Group Policy Management Editor

Conclusion

Now test logging off and back in on one of your Domain Windows 7 machines, and you should see that the local photos folder was created and the photos copied over from the share and your screen saver settings in place (assuming you allowed them to be viewed / changed). Wait the appropriate time and you should see your photos cycling in all their glory.