BigBastis Blog

Lokale Wetterdaten anzeigen mit der HTML5 Geolocation API und ASP.NET MVC

Introduction

user

Sebastian Gross

Sebastian Gross arbeitet in Bielefeld als Softwareentwickler für .NET und Java im Bereich Web.Als Fan der .NET-Plattform lässt er sich kein Userguppen Treffen und Community Event im Raum OWL entgehen.Dabei hat er eine besondere Vorliebe für das ASP.NET MVC Framework und für das Test Driven Development (TDD) entwickelt.


LATEST POSTS

Handling too long scrollspy menus 10th June, 2015

Java: Create ZIP archive 23rd March, 2015

.NET

Lokale Wetterdaten anzeigen mit der HTML5 Geolocation API und ASP.NET MVC

Posted on .

Wenn man heutzutage hipp sein will mit seiner Webseite sollte man irgendwelche coolen Features von HTML5 nutzen. Deswegen möchte ich euch in diesem kleinem Tutorial zeigen, wie ihr auf eurer Seite dem aktuellen Besucher sein lokales Wetter anzeigen könnt.

Um dieses Ziel zu verwirklichen benötigen wir folgende Daten bzw. Dienste:

  1. Die physische Position des Besuchers
  2. Einen Dienst der uns zu der Position des Besuchers die Wetterdaten liefert

Der erste Punkt ist schnell abgehackt, denn hier werden wir eins der tollen neuen HTML5 Features namens Geolocation API benutzen. Diese API liefert uns, vorausgesetzt der Browser unterstützt es, Koordinaten des aktuellen Besuchers der Webseite. Alle aktuellen Browser, auch der IE ab Version 9 unterstützt diese API.

Das Ganze läuft so ab, dass wir als Webseite den Browser nach den Koordinaten fragen, aber dieser uns diese nicht sofort herausrückt, sondern erst den Benutzer fragt ob er einverstanden ist, das sieht je nach Browser unterschiedlich aus, hier ein Beispiel aus dem FireFox 6:

Wenn der Benutzer hier auf die “Zugriff erlauben” Schaltfläche klickt bekommen wir ein Objekt mit einem Haufen an Informationen rund um die Position des Benutzers. Für uns ist an dieser Stelle aber nur die Adresse des Nutzers von Bedeutung.

Moment mal, woher weiß der Browser so ich bin?

Tja, das ist eine gute Frage, auf magische Weise weiß der Browser wo wir uns aufhalten, auch wenn wir grad mit einem Desktopcomputer auf der Seite sind, der kein GPS Chip verbaut hat (im Vergleich zum Handy – wo das ja klar sein sollte) und das auch noch _ziemlich_ genau!

Im ersten Augenblick könnte man denken der Browser macht es über die IP Adresse, aber nein die IP ist _Viel_ zu ungenau im Vergleich mit den echten Koordinaten.

So sendet der Browser (Firefox) nach eurer Erlaubnis folgende Daten an Google unter dieser Adresse: https://www.google.com/loc/json

"mac_address": "01-23-45-67-89-ab",
"signal_strength": 8,
"age": 0,
"SSID": "MyAccessPoint"

Weitere Informationen

Als Google mit ihren StreetView Autos durch die Gegend gefahren ist haben die nämlich auch die Namen und die genauen Positionen von den WLAN Netzwerken gespeichert, an denen sie vorbeigefahren sind. An Hand dieser Informationen versucht Google euch nun zu orten.

Wie komme ich nun an diese Informationen?

Glücklicherweise gestaltet sich dies für uns sehr einfach:

if (navigator.geolocation) {
  navigator.geolocation.getCurrentPosition(success, error);
} else {
  alert("Not Supported!");
}

Wenn der Browser diese API kennt werden die statischen Klassen Navigator und geolocation aufgerufen und hier die Methode getCurrentPosition aufgerufen, diese bekommt als Parameter einen Verweis auf die Methode die ausgeführt werden soll. Wenn das Ganze fehlschlägt (Kein Browsersupport) soll die display_error-Methode aufgerufen werden.

Die Funktion success bekommt einen Parameter mit, der alle relevanten Informationen enthält:
<pre>

function success(position) {
alert(position.coords.latitude);
alert(position.coords.longitude);
alert(position.address.city);
}

Für uns ist für das weitere Vorgehen aber nur der Name der Stadt wichtig.

Auslesen der Wetterinformationen

Es gibt diverse offene APIs die uns die Wetterdaten zu einer angegebenen Stadt liefern können, ich habe mich an dieser Stelle für die von Google entschieden, da diese offen ist und keine Registrierung voraussetzt.

Die API ist unter folgender URL zu erreichen:

http://www.google.com/ig/api?weather=[LOCATION]&hl=[LANGUAGE]

Hier müsst ihr lediglich die gewünschte Stadt und die gewünschte Sprache einsetzen. Als Antwort bekommt ihr eine XML, die die Wetterdaten enthält, und das nicht nur für jetzt, sondern für die gesamte nächste Woche, inklusive ausgeschriebener Formulierungen wie “Teils sonnig” oder “Meistens bewölkt”.

Und wenn euch das noch nicht genug ist, bietet Google auch gleich das passende Icon zu dem Wetter, dass ebenfalls aus dem XML.Status ausgelesen werden kann. Insgesamt gibt es 22 verschiedene Wetterzustände zu denen es jeweils auch ein passendes Icon gibt.

Moment, wie komme ich nun an diese Daten?

Es besteht nun nur noch ein kleines Problem. Die ganze Abfrage erfolgt beim Client, deswegen kennt nur der Client die Position des Benutzers. Wir müssen nun aber (im Hintergrund => Ajax) einen Request an den Google Dienst absenden um an die Wetterdaten zu kommen.

Leider können wir das nicht direkt aus dem Client machen, da die Browser es verbieten, Requests an andere Domains abzusenden als an die von der das Script geladen wurde. Das ganze schimpft sich “Same Origin Policy” und soll den Benutzer unter Anderem vor Cross-Site-Scripting-Attaken schützen.

Das bedeutet, dass wir den Umweg über den Server gehen müssen und uns auf dem Server eine kleine API anlegen müssen die unserem Script auf Anfrage die passenden Daten liefert.

Dies kann man z.B so implementieren:

private const string GOOGLE_WEATHER_API_URL =
	"http://www.google.com/ig/api?weather={0}&amp;amp;amp;amp;amp;amp;amp;hl=de";
public WeatherResult GetWeahterData(string city) {

    string api_url = string.Format(GOOGLE_WEATHER_API_URL, city);

    try {
        HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(api_url);
        HttpWebResponse res = (HttpWebResponse)req.GetResponse();
        StreamReader reader = new StreamReader(res.GetResponseStream());

        string response = reader.ReadToEnd();

        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.LoadXml(response);

        string temp = xmlDoc.SelectSingleNode("xml_api_reply/weather/current_conditions/temp_c").Attributes["data"].Value;
        string icon = xmlDoc.SelectSingleNode("xml_api_reply/weather/current_conditions/icon").Attributes["data"].Value;

        WeatherResult wRes = new WeatherResult(temp, city);
        wRes.Icon = icon;

        return wRes;
    } catch (Exception ex) {
        return null;
    }
}

Für den Response habe ich mir eine kleine Klasse gebastelt, die ich zu Json serialisiere und als Antwort zurückgebe:

    public class WeatherResult {
        public string Temperature { get; set; }
        public string City { get; set; }
        public string Icon { get; set; }

        public WeatherResult(string temp, string city) {
            Temperature = temp;
            City = city;
        }
    }

Das Ganze wird von dem ApiController aufgerufen:

    public class ApiController : Controller
    {
        //
        // GET: /Api/GetWeather

        public JsonResult GetWeather(string id)
        {

            WeatherResult res = new Tools.Weather.WeatherHelper().GetWeahterData(id);

            return Json(res, JsonRequestBehavior.AllowGet);
        }

    }

Was wir nun noch machen müssen ist unsere neu geschaffene API über einen Ajax Request aufzurufen. Hier habe ich jQuery benutzt um das Ganze zu vereinfachen:

404 Page not found

Error: Page not found

The requested URL was not found on this server.

Die get_weather-Funktion auf die ich hier im Erfolgsfall verweise ist nun dafür verantwortlich die vom Server erhaltenen Daten anzuzeigen, und dank dem zu Json serialisiertem WeatherResult-Objekt kann dies auch bequem erfolgen. Hier habe ich ebenfalls jQuery genutzt um mir die benötigten Referenzen auf die DOM-Objekte zu besorgen. Ein mögliches Ergebnis des Ganzen könnte ihr hier rechts sehen.

404 Page not found

Error: Page not found

The requested URL was not found on this server.

Sonst noch was?

Im Grunde wars das auch schon. Aber eine Kleinigkeit ist mir noch aufgefallen, und zwar kann es vorkommen, dass ihr keine Adressdaten von der Geolocation API bekommt, sondern nur Koordinaten. (Falls Google diese Daten nicht gelistet hat oder ähnliches).

In diesem Fall müsst ihr ein Reverselookup machen und die Koordinaten in eine Adresse umwandeln, da die Google Wetter API nur Ortsnamen, aber keine Koordinaten annimmt.

Glücklicherweise stellt und Google auch dafür eine API zur Verfügung, diese könnt ihr unter folgender URL erreichen:

http://maps.google.com/maps/api/geocode/json?latlng=[KOORDINATEN]sensor=true 

Hier könnt ihr sogar als Parameter angeben, ob ihr XML oder Json als Antwort haben wollt. Diese könnt ihr z.B. so nutzen:

404 Page not found

Error: Page not found

The requested URL was not found on this server.

Hier habe ich mir ein dynamic-Object generieren lassen aus dem übergebenen Json. Dazu habe ich diese Klasse hier genutzt.

Falls dieser Fall eintreffen sollte, braucht ihr übrigens nicht mit genauen Koordinaten bzw. Adressdaten zu rechnen, aber für unseren Zweck reicht es allemal.

kick it on dotnet-kicks.de

profile

Sebastian Gross

http://www.bigbasti.com

Sebastian Gross arbeitet in Bielefeld als Softwareentwickler für .NET und Java im Bereich Web.Als Fan der .NET-Plattform lässt er sich kein Userguppen Treffen und Community Event im Raum OWL entgehen.Dabei hat er eine besondere Vorliebe für das ASP.NET MVC Framework und für das Test Driven Development (TDD) entwickelt.

Comments
user

Author Thomas Baumann

Posted at 17:52 12. September 2011.

Nette Spielerei.
Aber ich wage es doch sehr zu bezweifeln dass es der Seriösität der Seite gut tut wenn gleich beim Besuchen der Browser (zu Recht!) zig Warnhinweise wirft / nach Erlaubnis fragt 🙂

Genau so wie IPv6. Zum mal anschaun und rum spielen ok, zum Verwenden nicht 🙂

user

Author Sebastian Gross

Posted at 17:57 12. September 2011.

Es ist wie so oft: „it depends“ Es gibt auch gute Anwendungsfälle für sowas, zb. Routenplanung, entweder ich muss meine Adresse und Co alles selber tippen oder klicke den Button „Automatisch ausfüllen“, nun fragt der Browser mich ob ich der Webseite meine Position verraten will und schwupp alles ausgefüllt, schnell und einfach.
Es sollte für den Benutzer natürlich nachvollziehbar sein wofür die Webseite die Daten haben will, dann ist es inho ok. Leider kann man in den Browser Popup nicht reinschreiben, warum er aufpoppt, aber vielleicht kommt das noch.

user

Author Timm Krause

Posted at 08:03 13. September 2011.

2 Dinge noch:

1. Man kann das Ergebnis der Google Maps API auch in XML zurückliefern lassen, finde ich etwas leichter zu handhaben:

http://maps.google.com/maps/api/geocode/xml?latlng=“ + latitude + „,“ + longitude + „&sensor=true

var xml = new WebClient().DownloadString(„http://maps.google.com/maps/api/geocode/xml?latlng=“ + latitude + „,“ + longitude + „&sensor=true“);

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);

city = xmlDoc.SelectSingleNode(„GeocodeResponse/result/address_component[3]/long_name“).InnerText;
country = xmlDoc.SelectSingleNode(„GeocodeResponse/result/address_component[6]/long_name“).InnerText;
countryCode = xmlDoc.SelectSingleNode(„GeocodeResponse/result/address_component[6]/short_name“).InnerText;
postalCode = xmlDoc.SelectSingleNode(„GeocodeResponse/result/address_component[7]/long_name“).InnerText;

2. Ich glaube, dass sich die Struktur des rekursiven Lookups verändern kann, dementsprechend ist eine harte Codierung nicht unbedingt erstrebenswert. Werde das vermutlich produktiv einsetzen, da werde ich dann mehr erfahren. 😉

@Thomas Baumann: Als Spielerei würde ich es nicht unbedingt abtun. Wenn das Publikum weiß, was es für einen Nutzen daraus hat, finde ich es völlig in Ordnung. Und zum anderen kommt es auf die Zielgruppe an: Firmenintern wieder eine ganz andere Geschichte.

user

Author Klaus Freyberg

Posted at 00:07 19. September 2011.

Noch eins .. Google’s Wetter API nimmt NICHT nur Orte, sonder auch lat, lon Koordinaten 🙂 Als Beispiel: google.com/ig/api?weather=,,,4790000,12040000. Das Problem hierbei ist jedoch, das mit einer Umkreissuche die DAten der nächstgelegenen Wetterstation dargestellt werden und das kann (z.B. bei beträchtlichen Höhenunterschieden) sehr unschön sein 🙂

Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

View Comments (5) ...
Navigation