Posted on Monday July 2011
It has obviously been a while since I’ve used the Google map API, as we no longer require a developer key to access the services (bonus!). This means I can freely go about the following:
Let’s prove our Google fu is cool first. Let’s go and grab a static map and return that.
The codes;)
$(function() {
navigator.geolocation.getCurrentPosition(function(pos) {
var lat = pos.coords.latitude;
var lon = pos.coords.longitude;
$('#mapImage').attr('src', 'http://maps.google.com/maps/api/staticmap?center=' + lat + ',' + lon + '&z=16&zoom=14&size=512x512&maptype=roadmap&sensor=false');
});
});
We can set the latitude and longitude using your modern browsers geolocation support.
Asking for a location should prompt with a security check.
That is all just great. Meanwhile back on the server we want to be passed in a latitude and longitude so we can find out where the sun is shining.
The server will expect latitude and longitude on the query string of the handler request.
The server code in its entirety is below. To be honest I am not proud of this code. It’s brittle. It’s ugly. It assumes waaaay too much about what Google might return. If I wrote this in production I would kick my arse. If this was production code I would:
Note also that Google allows content negotiation. We could have called that geo code url and got JSON back instead. It looks like this API does not support JSONP, but this one here might.
public class WeatherProxy : IHttpHandler
{
private HttpContext _context;
private readonly string _googleWeatherUrl = "http://www.google.com/ig/api?weather={0}";
private readonly string _googleGeoCodeUrl = "http://maps.googleapis.com/maps/api/geocode/xml?latlng={0}&sensor=false";
public void ProcessRequest(HttpContext context)
{
_context = context;
var latlon = _context.Request.QueryString["ll"];
var location = LookupCity(latlon);
var weatherXML = GetWeather(location);
var weatherJSON = ToJson(weatherXML);
WriteJsonResponse(weatherJSON);
}
private string LookupCity(string latlon)
{
// Ensure that no space exists between the latitude and longitude values when passed in the latlng parameter.
latlon = latlon.Replace(" ", "");
var xml = "";
using (var wc = new WebClient())
{
xml = wc.DownloadString(string.Format(_googleGeoCodeUrl, latlon));
}
// if we were good there would be an object model we could deserialize into
// or we would use some existing google geo code library.
// I'm sure there are many
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
// can you say nasty?
return doc.ChildNodes[1].ChildNodes[1].ChildNodes[4].FirstChild.InnerText;
}
private string GetWeather(string location)
{
using (var wc = new WebClient())
{
return wc.DownloadString(string.Format(_googleWeatherUrl, location));
}
}
private void WriteJsonResponse(string result)
{
_context.Response.Clear();
_context.Response.ContentType = "application/json";
_context.Response.AddHeader("content-disposition", "attachment;filename=weather.json");
_context.Response.Write(result);
_context.Response.Flush();
_context.Response.Close();
}
private string ToJson(string xml)
{
// Thank's NewtonSoft! You rock!
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
return JsonConvert.SerializeXmlNode(doc);
}
public bool IsReusable
{
get
{
return false;
}
}
}
Client side is not looking too crash hot either, to be honest. Some tidy up around the string concatenation would be nice.
<h2>How's the weather?</h2>
<div id="weather"> </div>
<div>
You're about here:
<image id="mapImage"></image>
</div>
$().ready(function () {
navigator.geolocation.getCurrentPosition(function (pos) {
var lat = pos.coords.latitude;
var lon = pos.coords.longitude;
$('#mapImage').attr('src', 'http://maps.google.com/maps/api/staticmap?center=' + lat + ',' + lon + '&z=16&zoom=14&size=512x512&maptype=roadmap&sensor=false');
$.getJSON('weatherproxy.ashx?ll=' + lat +',' + lon, function (data) {
$('' + data.xml_api_reply.weather.current_conditions.condition["@data"] + '
').appendTo('#weather');
$('The temperature is ' + data.xml_api_reply.weather.current_conditions.temp_c["@data"] + '°C
').appendTo('#weather');
$('Look’s a bit like this: ').appendTo('#weather');
});
});
});
And I lied about JSONP. It's _context.Response.Write(string.Format("{0}({1});", callback, json));