Erste Schritte mit SQL Server Data Services (SSDS) - Teil 2.1: Zugriff auf SSDS mittels SOAP (Anlegen einer Authority)

Die SQL Server Data Services (SSDS) sind in Microsofts "Software + Services" Strategie im Bereich der Entwickler-Services angesiedelt. In diesem mehrteiligen Blog möchte ich beschreiben, wie dieser Service zur Datenspeicherung genutzt werden kann. In Teil 1 bin ich bereits auf Registrierung und das Datenmodell eingegangen.

In diesem zweiten Teil möchte ich beschreiben, wie mittels des Simple Object Access Protocols (SOAP) auf SSDS zugegriffen werden kann. Dabe werde ich folgende Schritte beschreiben:

  1. Registrieren des SSDS Service
  2. Wahl des Übertragungsprotokolls (HTTP vs. HTTPS)
  3. Anlegen einer Authority

Schritt 1: Registrieren des SSDS Service

Um per SOAP-Webservices auf SSDS zugreifen zu können, muss der entsprechende Service im VisualStudio-Projekt registriert werden. Hierzu sind folgende Aktionen erforderlich:

  1. Im Projektmenü "Add Service Reference..." anklicken
  2. Eingabe der Adresse https://data.beta.mssds.com/soap/v1?wsdl.
  3. Umbenennen des voreingestellten Namens (ServiceReference1) für den Namespace in ssdsClient.

Das Grundgerüst des Hauptprogramms sollte nun inklusive aller Referenzen auf Namespaces wie folgt aussehen:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.ServiceModel;

using ssdsDemo.ssdsClient;

namespace ssdsDemo

{

class Program

{

static void Main(string[] args)

{

}

}

}

Schritt 2: Wahl des Übertragungsprotokolls (HTTP vs. HTTPS)

Grundsätzlich unterstützt SSDS beide Übertragungsprotokolle. In der Standardkonfiguration, die beim Setup wie oben beschrieben eingerichtet wird, wird HTTP gewählt. Nachdem in den folgenden Schritten User-Credentials (Benutzername und Passwort) übertragen werden müssen, empfiehlt sich allerdings eine Umkonfiguration zur Verwendung von HTTPS. Dies geschieht durch entsprechende Einträge in der Datei app.config, die sich im Projektverzeichnis befindet. In dieser Datei müssen die hervorgehobenen Zeilen in der Ursprungsdatei...

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

<system.serviceModel>

<bindings>

<basicHttpBinding>

<binding name="SitkaSoapEndpoint" ... > ...

<security mode="TransportCredentialOnly">

<transport clientCredentialType="Basic" proxyCredentialType="None"

realm="" />

<message clientCredentialType="UserName" algorithmSuite="Default" />

</security>

</binding>

</basicHttpBinding>

...

</bindings>

<client>

<endpoint address="https://data.beta.mssds.com/soap/v1"

binding="basicHttpBinding"

bindingConfiguration="SitkaSoapEndpoint"

contract="ssdsClient.ISitkaSoapService"

name="SitkaSoapEndpoint" /> ...

</client>

</system.serviceModel>

</configuration>

zu folgender Version geändert werden...

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

<system.serviceModel>

<bindings>

<basicHttpBinding>

<binding name="SitkaSoapEndpoint" ... > ...

<security mode="Transport">

<transport clientCredentialType="Basic" proxyCredentialType="None"

realm="" />

<message clientCredentialType="UserName" algorithmSuite="Default" />

</security>

</binding>

</basicHttpBinding>

...

</bindings>

<client>

<endpoint address="https://data.beta.mssds.com/soap/v1"

binding="basicHttpBinding"

bindingConfiguration="SitkaSoapEndpoint"

contract="ssdsClient.ISitkaSoapService"

name="SitkaSoapEndpoint" /> ...

</client>

</system.serviceModel>

</configuration>

Damit ist die Grundkonfiguration des Projekts schon abgeschlossen. Jetzt kann's mit den Webservice-Zugriffen losgehen.

Schritt 3: Anlegen einer Authority

Wie in meinem ersten Blog der Reihe beschrieben, stellt eine Authority das oberste Strukturierungselement für Daten in SSDS dar. Container und Entitys werden in jeweils einer bestimmten Authority angelegt. Zum Anlegen einer Authority ist zunächst die Definition des übergeordneten Scopes, in dem die Authority angelegt wird, erforderlich. Da die Authority das oberste Element des Hierarchiebaums ist, ist der Scope in diesem Fall der Service selbst. Formal wird hierzu ein leerer Scope angelegt. In diesem Scope kann dann die Authority angelegt werden. Hier das Gesamtlisting zum Anlegen einer Authority. Erklärungen zu einzelnen Codezeilen schließen sich an:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.ServiceModel;

using ssdsDemo.ssdsClient;

namespace ssdsDemo

{

partial class MySsdsProgram

{

private static string userName;

private static string password;

private const string sampleAuthorityId = "hsirtl-demo-auth";

static void Main(string[] args)

{

getUserCredentials();

createAuthority();

Console.WriteLine("Press any key.");

Console.ReadKey(true);

}

private static void createAuthority()

{

using (SitkaSoapServiceClient proxy = new SitkaSoapServiceClient("SitkaSoapEndpoint"))

{

proxy.ClientCredentials.UserName.UserName = userName;

proxy.ClientCredentials.UserName.Password = password;

Scope serviceScope = new Scope();

Authority auth = new Authority();

auth.Id = sampleAuthorityId;

try

{

proxy.Create(serviceScope, auth);

Console.WriteLine("Authority {0} created!", auth.Id);

}

catch (FaultException<Error> e)

{

if (e.Detail.StatusCode != ErrorCodes.EntityExists)

{

Console.WriteLine("Error: {0}:{1}", e.Detail.StatusCode, e.Detail.Message);

Console.WriteLine(e);

return;

}

Console.WriteLine("Authority {0} already existed", auth.Id);

}

catch (Exception e)

{

Console.WriteLine("General exception: {0}", e.ToString());

}

}

}

}

}

Im Folgenden nun also Erläuterungen zu den einzelnen Codezeilen:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.ServiceModel;

using ssdsDemo.ssdsClient;

namespace ssdsDemo

{

partial class MySsdsProgram

{

Die Definition der Namespaces wie bereits oben beschrieben. Die Klasse selbst habe ich umdefiniert zu "MySsdsProgram" und habe sie in der Hauptdatei als partial definiert. Grund hierfür ist, dass ich ein paar Hilfsmethoden (z.B. zum Erfassen von Benutzernamen und Passwort) ausgelagert habe.

private static string userName;

private static string password;

private const string sampleAuthorityId = "hsirtl-demo-auth";

Hier sind weren globale Variablen definiert, die in den später folgenden Beispielen noch verwendet werden. Hierzu gehören Benutzername und Passwort. Daneben noch die ID der Authority, die angelegt werden soll. Wichtig: In der aktuellen Version ist es nicht möglich, Authoritys zu löschen. Aus diesem Grund sollte die Authority sorgfältig festgelegt werden.

static void Main(string[] args)

{

getUserCredentials();

createAuthority();

Console.WriteLine("Press any key.");

Console.ReadKey(true);

}

Dies ist letztlich das Hauptprogramm. Es wird die Hilfsmethode getUserCredentials() aufgerufen. Diese setzt die oben definierten globalen Variablen userName und password, ruft die Methode zum Anlegen der Authority auf und wartet dann darauf, dass der Anwender eine Taste drückt.

private static void createAuthority()

{

using (SitkaSoapServiceClient proxy = new SitkaSoapServiceClient("SitkaSoapEndpoint"))

{

proxy.ClientCredentials.UserName.UserName = userName;

proxy.ClientCredentials.UserName.Password = password;

Hier wird nun Bezug auf den in Schritt 1 registrierten Webservice genommen. Da oben bereits der Namespace ssdsClient angemeldet wurde kann hier direkt der Webservice SitkaSoapServiceClient angesprochen werden. Im Service werden dann der Benutzername und das Passwort als Credentials gesetzt.

Scope serviceScope = new Scope();

Diese eine Zeile ist entscheidend. Hier wird ein "leerer" Scope gesetzt. Dieser ist später für den Service-Aufruf erforderlich. Da eine Authority angelegt werden soll, die keinen eigenen Scope (außer dem Service-Scope) besitzt, bleibt der Scope ansonsten leer.

Authority auth = new Authority();

auth.Id = sampleAuthorityId;

Eine neue Authority wird zunächst definiert. Dabei wird die ID der Authority auf den entsprechenden Wert der oben definierten globalen Variable gesetzt.

try

{

proxy.Create(serviceScope, auth);

Console.WriteLine("Authority {0} created!", auth.Id);

}

Hier erfolgt der Service-Aufruf. Im Service wird die Methode Create aufgerufen. Im Fehlerfall wird eine Exception geworfen, die in den Catch-Abschnitten (s.u.) behandelt wird. Im Falle des Anlegens einer Authority sind die häufigsten Fehler, dass entweder die Credentials falsch gesetzt wurden oder die Authority bereits existiert. Im Erfolgsfall erhält der Anwender eine positive Rückmeldung.

catch (FaultException<Error> e)

{

if (e.Detail.StatusCode != ErrorCodes.EntityExists)

{

Console.WriteLine("Error: {0}:{1}", e.Detail.StatusCode, e.Detail.Message);

Console.WriteLine(e);

return;

}

Console.WriteLine("Authority {0} already existed", auth.Id);

}

Hier werden Fehler des Webservices behandelt. Im Beispiel wird nur der Fall, dass die Authority bereits existiert, behandelt. Andere Service-Fehler werden generisch einfach ausgegeben.

catch (Exception e)

{

Console.WriteLine("General exception: {0}", e.ToString());

}

}

}

}

}

Diese Exception-Behandlung erfolgt bei allen anderen Fehlern des Service-Aufrufs. Bei fehlerhaften Credentials (Benutzername und/oder Passwort falsch) wird dieser Zweig der Fehlerbehandlung durchlaufen.

Ausführen dieses Programms führt nun, nachdem wir alles richtig gemacht haben, zu folgender, zugegebenermaßen recht unspektakulären Ausgabe:

Authority hsirtl-demo-auth created!Press any key.

Im nächsten Teil werde ich auf das Anlegen und Bearbeiten weiterer Objekte (Container, Entitys) eingehen. Stay tuned!

Ich bin Referent auf dem Microsoft Technical Summit 2008 - treffen Sie mich vor Ort!