SOAP Web Services konsumieren mit Dynamics NAV

Von | 7. Mai 2016

Hey Leute,

heute möchte ich meine Erfahrungen mit der Anbindung von externen Web Services an Dynamics NAV teilen. Dabei muss man grundsätzlich sagen, dass es zwei Formen von Web Services gibt. Zum Einen gibt es SOAP Web Services und zum Anderen gibt es REST Web Services.

Den Unterschied zwischen REST und SOAP kann man hier nachlesen: SOAP vs REST

Wenn Ihr REST Web Services konsumieren möchtet, dann kann ich nur die Serie von “Kauffmann” empfehlen. Hier wird erklärt, wie man das macht:

NAV Techdays 2015 – The Web Service Examples

Web Services Examples Part 1 – The Basic Pattern

Web Services Examples Part 2 – Verify E-mail Address

Web Services Examples Part 3 – Generate Barcode

Web Services Example Part 4 – Send SMS text message

Web Services Example Part 5 – DocuSign Integration

Web Services Example 6 – Office 365 Inbox

Web Services Example 7 – Call NAV OData Web Services (Part 1)

Im Bereich SOAP gibt es auch ein paar Beiträge von Vjeko: Web Services Black Belt: consuming NAV web services using pure C/AL

Hier geht es allerdings um Dynamics NAV Web Services, die durch C/AL konsumiert werden. Wenn man aber nun einen fremden Web Services in Dynamics NAV konsumieren möchte, ist C/AL wohl die falsche Wahl. Zu mindestens trifft das auf mich zu. Ich möchte heute erläutern, wie man einen Web Services mit einer selbst entwickelten Klassenbibliothek konsumieren kann.

Das bedeutet ich werde heute erläutern, wie man eine Klassenbibliothek mit C# in Visual Studio 2015 erstellt, diese dann in Dynamics NAV integriert und den Web Services dann aus NAV heraus konsumiert. Wir lagern also einen kleinen Teil der Business Logik aus und haben dennoch eine Integration in Dynamics NAV.  Wer kein Visual Studio besitzt, kann evtl. die Visual Studio Community Edition nutzen Visual Studio CE. Dies ist mit gewissen Auflagen verbunden, bzw. nur bestimmte Personenkreise oder Firmen dürfen das kostenlos nutzen.

Für unser heutiges Beispiel benötigen wir also einen Web Service. Jeder öffentliche Web Services kann dafür verwendet werden. Ich verwende für das Beispiel diesen SOAP Web Service: http://www.webservicex.net/geoipservice.asmx?WSDL

Dieser Web Service gibt uns im Idealfall Informationen zu einer IP zurück. Ich werde exemplarisch zeigen, wie man von einer IP Adresse den Ländercode zurückbekommt. Dafür öffne ich zuerst Visual Studio und erstelle ein neues Projekt und eine neue Klassenbibliothek:

1.) Ist Visual Studio geöffnet über das Menüband ein neues Projekt erstellen: Datei -> Neu -> Projekt…

Web Services - 1 Neues Projekt

2.) Im Fenster “Neues Projekt” folgendes tun: Visual C# -> Klassenbibliothek -> Name “SOAPWebServiceConnector”

Web Services - 2 Klassenbibliothek

3.) Ich benenne die Klasse von Class1 in SOAPWebServiveConnector um: Wichtig ist auch, dass die Klasse als “public” gekennzeichnet ist. Ist dies nicht der Fall so haben wir nachher keinen Zugriff auf die Funktionen der Klasse.

Web Services - 3 C Shape Projekt

Der Vorteil von Visual Studio ist ganz klar, dass ich hier eine Web Referenz hinterlegen kann. Damit ist es mir möglich schnell und effektiv auf alle Funktionen und Klassen eines Web Services zugreifen zu können. Dafür legen wir also eine neue Web Referenz an:

1.) Rechtsklick auf Verweise und die Aktion “Dienstverweis hinzufügen” auswählen:

Web Services - 4 Dienstverweis hinzufügen

2.) Im Fenster “Dienstverweis hinzufügen” auf “Erweitert…” klicken:

Web Services - 5 Dienstverweis hinzufügen_2

3.) In den Dienstverweiseinstellungen auf “Webverweis auswählen” klicken:

Web Services - 6 Dienstverweis hinzufügen_3

4.) In der URL die gewünschte SOAP Web Adresse angeben. In meinem Fall ist das: “http://www.webservicex.net/geoipservice.asmx?WSDL” und danach auf den kleinen Pfeil klicken. Nun wird die Web Service Definition importiert und gelesen. Wir hinterlegen zusätzlich einen Webverweisnamen “GeoIPWebService” und klicken dann auch “Verweis hinzufügen”.

Web Services - 7 Dienstverweis hinzufügen_4

In unserer Klasse “SOAPWebServiceConnector” schreiben wir nun ein paar Zeilen Programmcode. Ich lege hier eine öffentliche (von außen erreichbare) Methode GetCountryCodeByIP an.

  • Dabei bedeutet public, dass dies keine interne Funktion ist (vergleichbar mit der Eigenschaft Local in Codeunitfunktionen).
  • “string” definiert den Datentyp des Rückgabewertes. Ich gebe also einen Text zurück!
  • “GetCountryCodeByIP” ist der Methodenname.
  • “string IPAddress” definiert die Parameter. In diesem Fall habe ich nur einen Parameter. Benötige ich mehrere Parameter, so trenne ich diese mit einem Komma. Möchte ich einen Paramter wieder zurück an den Aufruf der Methode geben, dann schreibe ich “ref” vor den Datentyp.

Innerhalb der Funktion muss ich nun eine Verbindung zu dem Web Service aufbauen und den Ländercode als “return value” zurückgeben.

  • Dafür definiere ich eine neue lokale Textvariable “CountryCode”
  • Ich rufe den Konstruktor des WebService auf. Damit stelle ich eine Verbindung her und kann mit der erstellten Variable auf die Funktionen des Web Services zugreifen. Mehr über Konstruktoren kann man hier lesen (https://msdn.microsoft.com/de-de/library/ace5hbzh.aspx)
  • Ich rufe des Weiteren den Konstruktor der Klasse “GeoIP” auf, da dieser als Rückgabewert der Web Service Funktion erwartet wird.
  • Nun rufe ich die Funktion “GetGeoIP” mit meinem Parameter auf. Die Klasse “GeoIP” wird nun vom Web Service gefüllt.
  • Anschließend schreibe ich das Feld “CountryCode” aus der Klasse “GeoIP” in die Variable “CountryCode” und definiere den lokalen “CountryCode” als Rückgabewert.

Web Services - 8 Funktion zum Abruf des Web Services

Nun erstelle und veröffentliche ich meine DLL:

1.) Umstellen des Modus auf “Release”:

Web Services - 9 DLL erstellen

2.) Über das Menüband “Erstellen” -> “SOAPWebServiceConnector neu erstellen” auswählen.

Web Services - 10 DLL erstellen_2

3.) Den Projektordner öffnen und die kompilierten Dateien finden:

Web Services - 11 DLL erstellen_3

4.) Je nachdem ob das Addin/Klassenbibliothek Clientseitig (RunOnClient) läuft oder Serverseitig entsprechend im Server/Clientverzeichnis ablegen. In meinem Beispiel muss es im Serververzeichnis abgelegt werden. Benötigt wird lediglich die Datei “SOAPWebServiceConnector.dll”.

Web Services - 12 Addin ablegen

Web Services - 13 Addin ablegen_2

Nun ist das Addin / unsere Klassenbibliothek in Dynamics NAV verfügbar. Ich öffne den Entwicklungsclient erstelle eine neue Codeunit und integriere meine Klassenbibliothek.

Web Services - 14 Neue Codeunit

Ich erstelle hier eine Funktion “GetCountryCodeOfIPAddress und greife damit auf meinen Web Service zu. Ich übergebe eine IP-Adresse und lasse mir am Ende der Funktion per Nachricht den Ländercode zurückgeben. Auch in C/AL muss der Konstruktor einer .NET Klasse aufgerufen werden, damit wir auf die Funktionen der Klasse zugreifen können.

Web Services - 15 Codeunit Eigenschaften

Um die .NET Variable zu definieren, einfach folgende Schritte ausführen:

  • Die lokalen Variablen der Funktion öffnen
  • Als DataType “DotNet” auswählen.
  • Beim Subtype abtauchen.
  • Unter dem Register Dynamics NAV unseren SOAPWebServiceConnector suchen.
  • Anschließend unsere Klasse “SOAPWebServiceConnector” auswählen.
  • Mit “OK” bestätigen.

Web Services - 16 Dotnet Variable

Zu guter letzt einfach einen Bericht erstellen, der unsere C/AL Funktion aufruft:

Web Services - 17 Execute Web Service

Web Services - 18 Execute Web Service_2

Web Services - 19 Execute Web Service_3

Ich bin kein C# oder .NET Programmierer, aber wer hätte gedacht, dass es so einfach ist einen externen SOAP Web Service zu konsumieren. Für mich ist das der leichteste Weg um einen Web Service zu konsumieren. Sicherlich gibt es hier auch noch andere Wege, aber das gibt Euch sicherlich ein paar Ideen, wie man die Anbindung verschiedener Systeme lösen kann.

Hier gibt es wie gewohnt die NAV Objekte und das Visual Studio Projekt:

160507_ConsumeSOAPWebServiceInNAV.zip

SOAPWebServiceConnector.zip

6 Gedanken zu “SOAP Web Services konsumieren mit Dynamics NAV

  1. Natalie

    Sehr schöner Artikel zum Einstieg, danke dafür!
    Eine Frage hätte ich aber noch: WARUM genau ist C/AL zur Konsumierung von NAV-fremden Web Services nicht (oder nur weniger?) geeignet?

    Antworten
    1. Robert Beitragsautor

      Der Hauptgrund ist meiner Meinung nach der Folgende:
      NAV lässt keine Web Referenz zu, sowie es in Visual Studio der Fall ist. Dadurch ist die Integration m.E. viel schwieriger als es in Visual Studio ist.

      Des Weiteren gibt es ebenfalls zu viele .NET Restriktionen – Vjeko hat das schon gut beschrieben (http://vjeko.com/top-10-things-i-miss-in-net-interoperability-in-nav-2013) – vieles gilt auch für NAV 2016 noch!

      Zu guter letzt habe ich mich auch mit dem Beitrag von Vjeko befasst, indem er einen NAV Page Web Service konsumiert. Da wird es sehr schnell kompliziert. Man muss sich einfach mal das Objekt herunterladen (http://www.mibuso.com/dlinfo.asp?FileID=1472). Ich halte eine kleine Klassenbibliothek für wesentlich einfacher, aber das ist nur meine subjektive Meinung.

      Antworten
      1. Daniel

        Wenn man weiß wie, dann ist C/AL nicht die falsche Wahl. Visual Studio bietet zwar durch die Web Referenz eine komfortable Möglichkeit, aber benötigt wird sowas nicht. Zudem wird die Codepflege deutlich erschwert und selbst für kleine Anpassungen muss man ständig die DLL neu generieren.
        Im Standard gibt es bereits in der Codeunit 1297 einen Webservice Aufruf, den man für seine zwecke auch umfunktionieren kann.
        Ich habe bspw. den Response in ein XMLPort übergeben und dies zu validieren und direkt eine Tabelle zu füllen. Sowas wäre mit einer externen DLL nur schwer oder gar nicht möglich.
        Ich denke auf den ersten Blick ist es im VS schon leichter weil vieles automatisiert ist und wenn man von C/AL nicht so die Ahnung hat dann sowieso. Aber wenn es möglich ist, dann sollte man schon in NAV bleiben.

        Antworten
        1. Robert Beitragsautor

          Hi Daniel,

          danke für deine Meinung. Du sprichst da einige wichtige Punkte an auf die ich hier gar nicht eingegangen bin. Ich kann natürlich auch in NAV die SOAP XML Anfrage ausprogrammieren und auch die Antwort lesen. Das hat auch seinen Charme.

          Visual Studio hat neben der Web Reference Funktion auch ein paar nennenswerte Nachteile. Dazu gehört auch, dass man bei Fehlern schwer prüfen kann, welche genaue XML Anfrage gestellt wurde und wo der Fehler genau liegt. In NAV ließe sich die Anfrage beispielsweise in eine Datei schreiben um diese dann zwecks SOAPUI oder ähnlichen Programm zu prüfen. Auch ist die Umwandlung zu Proxyklassen in Visual Studio nicht perfekt! Zusätzlich benötigt man die DLL auch im Server oder Clientverzeichnis von Dynamics NAV (je nach Anforderung).

          Man darf aber nicht vergessen, dass die integrierte Funktion der Web Reference schon ziemlich komfortabel ist. Das bietet mir NAV nicht. Da benötige ich schon einiges an Code um das entsprechend abzubilden.

          Für welchen Weg man sich auch entscheidet, bleibt letzten endlich jedem selbst überlassen. Ich persönlich finde die Lösung als Klassenbibliothek aber definitiv nicht schlecht. Dabei berücksichtige ich auch, dass so wenig Business Logik in Visual Studio stattfindet und nur die Aufrufe der Webservicefunktionen von Visual Studio durchgeführt wird. Auch die Übertragen von Tabellen ist kein Problem, man kann schließlich auch eigene Klassen mit den notwendigen Werten in seine Klassenbibliothek integrieren und diese als Listparameter mit NAV austauschen. Das ist dann stark vergleichbar mit der Parameterübergabe eines XMLPort. Deine Argumente kann ich aber dennoch nachvollziehen!

          Mein Fazit: Es gibt hier kein Schwarz oder weiß! Beide Varianten haben Vor- und Nachteile.

          VG
          Robert

          Antworten
  2. Marcel

    Sehr interessanter Artikel! Ich hätte allerdings eine Frage: Wenn ich einen Web Service konsumieren will, der durch ein Passwort geschützt ist, wie übermittle ich da die Login-Daten? Beim Erstellen des Webverweises gibt es ja leider keine Möglichkeit dazu…

    Antworten
    1. Robert Beitragsautor

      Hallo Marcel,

      ich kann nicht für alle Webservices sprechen. Meine Erfahrungen sind allerdings folgende:
      a) Zugangsdaten müssen im Konstruktor als Parameter angegeben werden.
      b) Zugangsdaten müssen bei spezifischen Aufruf einer Funktion des Webservices übergeben werden.

      Bei beiden Varianten ist es möglich, dass die Zugangsdaten per String übertragen werden oder das man eine Klasse erstellen und mit den Zugangsdaten füttern muss. Die Webservice Definition sollte eigentlich immer öffentlich sein, ohne das Zugangsdaten angegeben werden. Damit kann man auch immer die Webservice Referenz in Visual Studio hinzufügen.

      Falls du das nicht so einfach heraus bekommst, wie das bei deinem Webservices funktioniert, dann musst du die Dokumentation vom Webservices Veröffentlicher anfragen.

      Antworten

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.