Wortschatz Leipzig Webservice mit C# nutzen

C# Sourcecode IconIn dem hier verlinken Artikel habe ich bereits eine kleine C# Library zur Verfügung gestellt, mit der man auf den Thesaurus Webservice des Wortschatz Leipzig Projekts zugreifen kann.

In diesem Artikel möchte ich nun kurz beschreiben, welche „Hürden“ es zu meistern galt, um den Webservice von C# aus ansprechen zu können. Trotz dessen, dass das Wortschatz Leipzig Team eine WSDL-Datei für Ihren Webservice zur Verfügung stellt, ist es mit dem reinen Hinzufügen einer Web- oder ServiceReference im Visual Studio nämlich nicht getan.

Wortschatz Leipzig Webservice einbinden

Als erstes muss eine ServiceReference auf den gewünschten Webservice erstellt werden. Für diesen Artikel nehmen wir mal den Thesaurus Webservice. Der Pfad zur WSDL-Datei, die man zum Anlegen der ServiceReference benötigt, lautet:

http://wortschatz.uni-leipzig.de/axis/services/Thesaurus?wsdl

Info: (Zum weiteren Verständnis.) Ich habe die ServiceReference “ThesaurusClient” genannt.

Nun sollte man denken, dass alles erledigt sei und man mit einem Instanzieren der ThesaurusClient-Klasse und einem schlichten Aufruf der execute()-Funktion alles getan hätte. Weit gefehlt!

Erstellen des Clients

Zuerst müssen wir den Webservice-Client instanziieren und konfigurieren. Der Webservice des Wortschatz Projekts erfordert nämlich Zugangsdaten.

ThesaurusClient service = new ThesaurusClient();
service.ClientCredentials.UserName.UserName = "anonymous";
service.ClientCredentials.UserName.Password = "anonymous";

Aufrufparameter erstellen

Im nächsten Schritt müssen die Aufrufparameter erstellt warden. Die execute()-Funktion des Webservice nimmt 3 Parameter an – das Wort zu dem Synonyme geliefert werden sollen, die maximale Anzahl („Limit“) an Synonymen und das Wörterbuch („corpus“), in dem die Synonyme gesucht werden sollen. Leider kann man diese nicht als string, int, string übergeben, sondern muss diese in einer speziellen Datenstruktur übergeben.

DataMatrix matrix = new DataMatrix();
List<DataVector> vector = new List<DataVector>();
DataVector dv = new DataVector();
dv.Add("Wort");
dv.Add("Auto");
vector.Add(dv);
dv = new DataVector();
dv.Add("Limit");
dv.Add(100);
vector.Add(dv);
matrix.AddRange(vector);

RequestParameter request = new RequestParameter();
request.corpus = "de";
request.parameters = matrix;

Der obige Code gibt also maximal 100 Synonyme zu dem Wort “Auto” zurück und schlägt dabei im Wörterbuch “de” (für Deutschland) nach.

Aufruf des Webservice

Nun muss noch die eigentliche Abfrage an den Webservice erfolgen. Doch auch hier versteckte sich noch ein Kniff. Damit die Zugangsdaten („anonymous:anonymous“) orentlich an den Wortschatz Webservice übergeben werden, muss der Aufruf der execute()-Funktion in einem OperationContextScope erfolgen und die Header der Anfrage an den Webservice manipuliert werden.

using (OperationContextScope scope = new OperationContextScope(service.InnerChannel))
{
   var httpRequestProperty = new HttpRequestMessageProperty();
   httpRequestProperty.Headers[System.Net.HttpRequestHeader.Authorization] = "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes(service.ClientCredentials.UserName.UserName + ":" + service.ClientCredentials.UserName.Password));
   OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestProperty;

   //Nun erfolgt erst der eigentliche Aufruf des Wortschatz Webservice
   ResponseParameter resp = service.execute(request);
}

Auswerten der Antwortdaten aka Synonyme

Auch beim Auslesen der Daten gab es Probleme. Zwar funktionierte an diesem Punkt die Abfrage erfolgreich, jedoch konnte das Ergebnis nicht korrekt geparst werden, sodass die Datenstruktur, die eigentlich die Antwort des Webservice enthalten sollte, leer war.

An dieser Stelle habe ich eine Quick’n’Dirty-Lösung mit einer RegularExpression angewandt. Zuerst einmal brauchen wir jedoch das Raw-XML, also die Antwort des Wortschatz-Webservice. Um an dieses zu gelangen benötigten wir einen MessageInspector für unseren Webservice-Client.

Hierzu fügen wird zuerst die beiden nachfolgenden Klassen hinzu.

private class InspectorBehavior : IEndpointBehavior
{
   public string LastRequestXML
   {
      get
      {
         return myMessageInspector.LastRequestXML;
      }
   }

   public string LastResponseXML
   {
      get
      {
         return myMessageInspector.LastResponseXML;
      }
   }

   private MyMessageInspector myMessageInspector = new MyMessageInspector();
   public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
   {
   }

   public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
   {
   }

   public void Validate(ServiceEndpoint endpoint)
   {
   }

   public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
   {
      clientRuntime.MessageInspectors.Add(myMessageInspector);
   }
}

private class MyMessageInspector : IClientMessageInspector
{
   public string LastRequestXML { get; private set; }
   public string LastResponseXML { get; private set; }

   public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
   {
      LastResponseXML = reply.ToString();
   }

   public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
   {
      LastRequestXML = request.ToString();
      return request;
   }
}

Nun müssen wir den Inspector noch nach dem intanziieren unseres ThesaurusClient aktivieren.

ThesaurusClient service = new ThesaurusClient();
var requestInterceptor = new InspectorBehavior();
service.Endpoint.Behaviors.Add(requestInterceptor);

Jetzt können wir nach dem Aufruf der execute()-Funktion die XML-Datei abfragen, die wir vom Wortschatz-Webservice zurückerhalten haben.

ResponseParameter resp = service.execute(request);
string requestXML = requestInterceptor.LastRequestXML;
string responseXML = requestInterceptor.LastResponseXML;

Jetzt, wo wir die Antwort des Wortschatz Leipzig Service als XML zur Verfügung haben, können wir die Synonyme mit einer kleinen Regular Expression herausparsen und in einer Liste zur Verfügung stellen.

Regex reg = new Regex("<ns\\d+:dataRow>(.*?)</ns\\d+:dataRow>");
MatchCollection mc = reg.Matches(responseXML);

List<string> synonymList = new List<string>();

if (mc.Count > 0)
   synonymList.AddRange((from Match m in mc select m.Groups[1].Value));

Alle gefundenen Synonyme befinden sich nun in der Liste „synonymList“.

Fazit & Download

Das war es auch schon. Ich hoffe ich konnte dem ein oder anderen suchenden Helfen. Wer möchte kann sich den ganzen Quelltext hier in dem Artikel zur Library oder bei GitHub herunterladen.

4 Kommentare

  1. Ich stecke zwar noch nicht mehr so ganz in der C# Programmierung drin, aber macht es nicht mehr Sinn, die Antwort als XML zu parsen statt via Regex?

    Habe das Ganze am Wochende mal für PHP umgesetzt (siehe http://www.myseosolution.de/php-wrapper-wortschatz-uni-leipzig-api/ für Erklärung + Code), da nimmt einem der integrierte SOAP Client zum Glück die Arbeit weitestgehend ab :)

    Viele Grüße
    Pascal

    • Hallo Pascal,

      der Standard Webservice Client zickte im Visual Studio ja ein bisschen rum. Sicher wäre eine XML-Variante vermutlich sauberer, aber wie ich im Artikel schrieb handelt es sich um eine “Quick’n’Dirty”-Lösung. XML geht auch, Regex ist aber einfach schneller/kürzer zu schreiben gewesen. Und da es hier nicht auf Zeit ankommt, ist die ggf. etwas höhere Laufzeit/der erhöhte Rechenaufwand durch Regex zu vernachlässigen.

  2. Danielsays:

    Sehr Interessant, es gibt jedoch auch die möglichkeit sich den Wortschatz runterzuladen als SQL-Dump. Das ist die bessere Alternative vorallem wenn man ihn z.B in ein Tool einbauen will. Ihr müsst einfach bei den Verantwortlichen da anfragen die geben euch dann den Download Link

  3. Der Artikel ist echt interessant! Weiter so :)

Schreibe einen Kommentar zu Raffi Antworten abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Sie dient nur dem Spamschutz.