Die Idee ist ganz simpel. Da SharePoint nun Geo-Location Felder bietet (siehe mein Blogeintrag zu Geo-Location) möchte ich die Koordinaten einer Adresse automatisch über ein Webservice von Google ermitteln lassen und in die Liste eintragen. Dafür verwende ich einen Workflow der beim Anlegen eines Listen-Items automatisch gestartet wird.
Zunächst wird die Liste im Visual Studio mit dem Editor angelegt:
Zu beachten sind die beiden Felder “Location” und das hidden-Field: “LocationTXT”. Dieses wird aufgrund einer Einschränkung der Workflow Engine benötigt. Location-FieldValues können nicht per Workflow gesetzt werden. Dazu später noch mehr.
Workflow
Der Workflow wird zusammen mit der Liste in einem SharePoint Projekt definiert. Im wesentlichen werden aus dem aktuellen Item die Felder Straße, Ort, PLZ und Land ermittelt und in Workflow Variablen geschrieben.
Dann setze ich die URL für den Serviceaufruf zusammen. Im ersten Schritt wird die Adressangabe zusammen gesetzt:
Der gesamte Ausdruck ist: Strasse.Replace(" ","") +"+" + PLZ + "+" + Ort + "+" +Land
Google erwartet alle Wörter durch + getrennt.
Die gesamte Uri wird so zusammengesetzt:
Der Ausdruck ist: "http://maps.googleapis.com/maps/api/geocode/json?address=" + URLAddress
Danach wird ein http-Send aufgerufen. Als URI wird der zuvor gebildete Ausdruck verwendet. Wird das Googl API mit unserer Adresse in Wien, 150 Märzstrasse 1, aufgerufen erhalten wir folgendes Json-Objekt:
{
"results" : [
{
"address_components" : [
{
"long_name" : "1",
"short_name" : "1",
"types" : [ "street_number" ]
},
{
"long_name" : "Maerz Street",
"short_name" : "Maerz Street",
"types" : [ "route" ]
},
{
"long_name" : "Rudolfsheim-Fünfhaus",
"short_name" : "Rudolfsheim-Fünfhaus",
"types" : [ "sublocality_level_1", "sublocality", "political" ]
},
{
"long_name" : "Vienna",
"short_name" : "Vienna",
"types" : [ "locality", "political" ]
},
{
"long_name" : "Vienna",
"short_name" : "Vienna",
"types" : [ "administrative_area_level_1", "political" ]
},
{
"long_name" : "Austria",
"short_name" : "AT",
"types" : [ "country", "political" ]
},
{
"long_name" : "1150",
"short_name" : "1150",
"types" : [ "postal_code" ]
}
],
"formatted_address" : "Maerz Street 1, 1150 Vienna, Austria",
"geometry" : {
"location" : {
"lat" : 48.2006027,
"lng" : 16.3370802
},
"location_type" : "ROOFTOP",
"viewport" : {
"northeast" : {
"lat" : 48.20195168029149,
"lng" : 16.3384291802915
},
"southwest" : {
"lat" : 48.1992537197085,
"lng" : 16.3357312197085
}
}
},
"types" : [ "street_address" ]
}
],
"status" : "OK"
}
D.h. im Object “geometry” finden wir Länge und Breite der Position. Nun kann der Response in seine Einzelteile zerlegt werden. Hierfür bietet die Activity “GetDynamicValueProperties” die richtigen Möglichkeiten. Es wird der Pfad im JSon-Objekt angegeben und der Inhalt in eine Variable geschrieben. Die Einstellungen sind hier:
Nun stehen uns innerhalb des Workflows die Variablen lat und lng mit den Werte zur Verfügung.
Update des Geo-Location Feldes
Innerhalb einer Listen Deklaration mit XML kann ein Wert für ein Location Feld mit “POINT(lng, lat)” angegeben werden. Leider kann ich diesen Textausdruck nicht mittels ItemUpdate aus dem Workflow heraus in die Liste schreiben. Es gibt noch die Möglichkeit per REST-API Werte zu schreiben, aber ob über diesen Weg die Location geschrieben werden kann ist fraglich. Ich habe es noch nie probiert.
Nachdem meine Lösung bereits eine Farm-Solution ist, habe ich einen kleinen Umweg über einen Event-Receiver gewählt. Der Workflow schreibt in das Feld “LocationTXT” die Variablen Inhalte von “lng” und “lat”, zur Trennung wird ein Pipe (|) verwendet. Der Event-Receiver erstellt den Location-Datentyp und schreibt diesen in das Location-Feld.
Der Code für den Event-Receiver:
public class SetLocationFieldValue : SPItemEventReceiver
{
/// <summary>
/// An item is being updated.
/// </summary>
public override void ItemUpdating(SPItemEventProperties properties)
{
base.ItemUpdating(properties);
string txt = (properties.AfterProperties["LocationTXT"] ?? "").ToString();
string[] teile = txt.Split('|');
double lat = 0;
double lng = 0;
double.TryParse(teile[0].Replace(".",","), out lng);
double.TryParse(teile[1].Replace(".", ","), out lat);
SPFieldGeolocationValue v = new SPFieldGeolocationValue(lat, lng);
properties.AfterProperties["location"] = v;
}
}
Als Ergebnis haben wir nun eine Liste, in der automatisch die Geo-Location Information aus der eingegebenen Adresse ermittelt wird.
Dieses und ähnliche Beispiele für SharePoint – CrossPlattform stelle ich am 4.11.2014 in Wien bei der ADXC, der Konferenz für Cross Plattform Development (www.adcx.ms/wien) vor.