Donnerstag, 4. Dezember 2008

entwickler.com Magazine Konferenzen Akademie Entwickler-Forum Jobbörse Bücher
Software & Support Verlag




April 2006
aus Der Entwickler Ausgabe: 3.2003
Brückenbauer
Web Services mit Borland Delphi 7
von Andreas Kosch

Auch wenn die Marketing-Maschinerie der großen Software-Häuser den Mund beim Thema Web Services wieder einmal zu voll genommen hat, lässt sich der zwar langsame, aber unübersehbare Siegeszug nicht leugnen. Allerdings sind Web Services nicht das Allheilmittel, das alle aktuellen Probleme in der Software-Welt löst - in ihrem primären Aufgabengebiet sind sie jedoch unschlagbar. Der Artikel wirft ein Streiflicht auf die Möglichkeiten der aktuellen Delphi-Version und stellt die potentiellen Nutznießer (von der Windows-Anwendung bis hin zum PocketPC) mit einem Beispiel vor.


Für die Frage Was ist ein Web Service überhaupt? hat die Web Service Description Working Group (W3C) eine verblüffend einfache Antwort definiert: Ein Web Service ist eine durch eine URI (Uniform Ressource Identifier) identifizierbare Software-Anwendung oder eine Komponente, deren Interfaces (Schnittstellen) dazu dienen, über standardisierte XML-Aufrufe (SOAP) eine direkte Kommunikation zwischen Software-Anwendungen durch das Austauschen von als XML vorliegenden Daten zu ermöglichen, wobei dafür Internet-basierende Protokolle verwendet werden. Dieser Satz reicht aus, um den Kern der Web Services klar herauszuschälen. Es geht darum, dass Software-Anwendungen völlig unabhängig von der genutzten Programmiersprache und der verwendeten Hard- und Software-Plattform miteinander kommunizieren können. Nun werden Sie vielleicht das Argument in die Runde werfen, dass es dies ja auch schon früher in Form von Windows DNA, CORBA, Java RMI usw. gegeben hat. Das Neue an der Sache ist allerdings, dass nun der Fokus auf den von breiter Front akzeptierten Industriestandards wie XML und HTTP liegt, denn das Ganze ist nur dann von Erfolg gekrönt, wenn alle beteiligten Hersteller über ihren eigenen Schatten springen und die Kompatibilität der je-weiligen Implementierungen in den Vordergrund stellen. Auch wenn es am Anfang nicht so ausgesehen hat, ziehen nun die großen Drei Microsoft, IBM und Sun alle am gleichen Seil - und was noch wichtiger ist, auch in die gleiche Richtung. Und da in der Web Services Interoperability Organization (WS-I) neben den großen Drei auch Firmen wie Intel, Oracle, SAP, HP, BEA Systems und Fujitsu vertreten sind, darf man wohl davon ausgehen, das der Weg am Ende auch zum Ziel führt.


Schaut man sich nun um, welche Firmen in welchen Bereichen bereits Heute umfassend auf Web Services zurückgreifen, fällt auf, dass viele Hardware-Hersteller wie DELL oder HP intensiven Gebrauch davon machen. Bei diesen - untereinander im harten Wettbewerb stehenden Firmen - spielt die Effizienz eine wesentliche Rolle. In derart großen Firmen ist eine inhomogene IT-Infrastruktur zu finden, die miteinander verbunden werden muss, um im Wettlauf zu immer kürzeren Fertigungszeiten bestehen zu können. Und hier schlägt die große Stunde der Web Services - denn sie sind der ideale Kitt, um die verschiedenen Systeme und Programmiersprachen miteinander verbinden zu können. Beim firmeninternen Einsatz fallen die momentanen Lücken (Security, Transaction, Routing, Message Queueing usw.) in der Web Services-Welt nicht auf, daher verwundert es nicht, wenn in Europa fast 90 Prozent aller Web Services-Anwendungen nur firmenintern laufen. Allerdings arbeiten alle beteiligten Software-Häuser am GXA-Standard (Global XML Web Services Architecture), um diese Lücken so schnell wie es in einer derart großen Runde geht, zu schließen. Dieser Hintergrund ist auch die Erklärung für den deutlich sichtbaren Effekt, dass eine Entwicklungsumgebung umso besser für die Entwicklung von Web Services geeignet ist, je Neuer sie ist. Damit das nicht alles graue Theorie bleibt, greife ich auf ein Beispiel zurück. Beachten Sie bitte, dass ich hier nur einen Bruchteil der Möglichkeiten vorstellen kann. Weitere Alternativen für Delphi 5, 6 oder 7 (Professional oder Enterprise) stehen als COM+ Web Services [1] oder über das kostenfrei erhältliche Microsoft SOAP Toolkit [2] zur Verfügung.

Der Delphi 7-Web Service
Angenommen, Sie erhalten die Aufgabe, über einen mit Delphi 7 entwickelten Web Service bestimmte Funktionen für verschiedenartige Clients des eigenen Unternehmens bereitzustellen. Als Client müssen Sie sowohl mit einer Delphi-Anwendung, einer in VB.NET geschriebenen .NET-Anwendung, einer in C# geschriebenen ASP.NET-Anwendung als auch mit einer in VB.NET geschriebenen Anwendung für den PocketPC rechnen. Diese Aufzählung mag imposant sein, aber muss Sie nicht wirklich beeindrucken. Denn für einen Web Service ist es völlig unerheblich, wer alles auf ihn zugreift. Wir dürfen somit unsere Datenstruktur als Delphi-Klasse verpacken, auch wenn Delphi-fremde Anwendungen damit arbeiten müssen. Und da alles in der eigenen Firma bleibt, ist die Anzahl der gleichzeitig darauf zugreifenden Anwender keine Unbekannte. Solange sich die Anzahl im zweistelligen Bereich bewegt und die Web Services zustandslos bleiben können, müssen wir uns um die Themen Skalierbarkeit und Session-Verwaltung nicht kümmern, sodass ich direkt die Fähigkeiten der Experten von Delphi 7 ausnutzen kann. Falls Sie jedoch diese beiden Kriterien nicht von vornherein ausschließen dürfen, sollten Sie sich die Web Services-Fähigkeiten von .NET genauer anschauen.


Fangen wir nach dieser langen Vorrede nun endlich mit der Arbeit an. In Delphi 7 Enterprise rufe ich dafür zuerst die Objektgalerie auf, um ein neues Projekt für eine SOAP-Server-Anwendung zu beginnen (Abb. 1). An dieser Stelle will Delphi zuerst von Ihnen wissen, in welcher Form das Server-Modul gestaltet werden soll. Im Gegensatz zu DCOM- und COM+-Objekten muss der Host für den Web Service bereits laufen, bevor ein Client eine Verbindung herstellt. Aus diesem Grund stellt der Delphi-Experte auch nur solche Module zur Auswahl bereit, die in einen bereits laufenden Webserver eingebunden werden können. Da in meinem Beispiel der Web Service im IIS (Internet Information Service) von Windows laufen soll, greife ich zu einer ISAPI-DLL. Hinter dem Internet Information Service Application Programming Interface (ISAPI) verbirgt sich die Schnittstelle, die das Einbinden eigener DLLs in den IIS erlaubt.


Abb. 1: Die Experten von Delphi 7 machen fast die ganze Arbeit

Wenn ich den zweiten Dialog mit der Voreinstellung auf das ISAPI-Modul mit OK bestätige, legt der Experte das Web Modul mit den drei Komponenten an und fragt sofort über ein weiteres Dialogfenster nach, ob auch gleich das Interface für das SOAP-Modul erzeugt werden soll. Da sich dahinter nur die für das Simple Object Access Protocol zuständige Software verbirgt, ist damit der Web Service gemeint. Der letzte Dialog Neuen Web Service hinzufügen möchte von Ihnen wissen, welchen Namen das Kind erhalten soll, wobei ich dort auch die Checkbox Beispiel-Methoden generieren angekreuzt habe, bevor der Mausklick auf den OK-Button die Arbeit des Experten abschließt. Das von Delphi generierte Ergebnis speichere ich unter dem Projektnamen DE2003WS.dpr ab, um das Ganze dann sofort zu kompilieren. Die 1075 kByte große DLL kann nun getestet werden - dafür muss ich allerdings erst ein virtuelles Webverzeichnis im IIS anlegen, wobei ich dafür den Verzeichnisnamen DE2003 verwende. Die dazu notwendigen Schritte zeigt die Abbildung 2.


Abb. 2: Das virtuelle Webverzeichnis DE2003 wird angelegt

Ich kopiere nun die vorhin kompilierte DLL DE2003WS.dll in das Festplattenverzeichnis, welches ich für das gerade angelegte virtuelle Webverzeichnis DE2003 ausgewählt habe. Ist das erledigt, steht dem ersten Aufruf im Internet Explorer (oder einem sonstigen Webbrowser Ihrer Wahl) nichts mehr im Wege. In meinem Beispiel rufe ich dafür die URL http://192.168.10.1/DE2003 auf und da ich im Eigenschaftsdialog des virtuellen Webverzeichnisses das Durchsuchen dieses Verzeichnisses erlaubt habe (Abb. 2), kann ich die DLL mit einem Mausklick auswählen. Als Belohnung für meine Mühen liefert mir der mit Delphi 7 geschriebene Web Service seine Funktionsbeschreibung in Form der Service Info-Seite zurück (Abb. 3).


Abb. 3: Der erste Funktionstest

In der Service Info-Seite kann der Anwender auch den Link für die WSDL-Beschreibung anklicken. Um zu verstehen, warum die WSDL (Web Service Description Language) für den Client benötigt wird, ist ein kurzer Blick auf die Abbildung 4 hilfreich. Auf den mit Delphi 7 geschriebenen Web Service soll ein beliebiger Client zugreifen, wobei dieser auf einem beliebigen Betriebssystem in einer beliebigen Sprache geschrieben sein darf, solange dort der Zugriff auf einen Web Service unterstützt wird. Die WSDL übernimmt in diesem Szenario die Aufgabe, einen maschinenlesbaren Bauplan für die Zugriffsklassen (Proxy-Klasse) zu liefern. Von diesen ganzen Details bleiben Sie jedoch verschont, da der Delphi-Experte alle notwendigen Komponenten automatisch verbaut und konfiguriert hat.


Abb. 4: Das dahinter liegende Prinzip

Allerdings fehlt zur Zeit noch die gewünschte Nutzfunktion - sodass ich in der Implementierungs-Unit DE2003ServiceImpl.pas die durch den Kommentar hervorgehobenen Programmzeilen nachrüste. Der Web Service soll beim Aufruf der Methode echoMyEmployee die vom Client erhaltenen Daten mit neuen Werten zurückliefern, indem dazu eine neue Instanz der Klasse TMyEmployee an den Aufrufer zurückgeliefert wird:

function TDE2003Service.echoMyEmployee(
const Value: TMyEmployee): TMyEmployee; stdcall;
begin
Result := TMyEmployee.Create;
// von Hand nachgerüstet
Result.LastName := Value.LastName + ' (Return)';
Result.FirstName := Value.FirstName + ' (Return)';
end;

Wenn ich nun das Projekt neu kompiliere und die neue DLL in das Verzeichnis für das virtuelle Webverzeichnis DE2003 kopieren will, erhalte ich jedoch ein Veto vom Betriebssystem. Da der IIS die alte DLL-Fassung noch im Arbeitsspeicher hält, muss ich zuerst den Eigenschaftsdialog des virtuellen Webverzeichnisses aufrufen, um dort den Button Entladen anzuklicken. Erst dann, wenn der Web Service mit .NET geschrieben wird, entfällt dieser Schritt, da ein .NET-Web Service automatisch das so genannten Shadow Copy nutzt, um geladene DLLs ohne Herunterfahren austauschen zu können.

COM+ 1.5 Web Services
Ab Windows XP Professional mit installiertem .NET Framework und ab dem brandneuen Windows Server 2003 steht eine Technologie zur Verfügung, die aus einem alten COM+-Objekt allein durch das Ankreuzen einer Checkbox in einem Betriebssystemdialog einen waschechten Web Service macht. Dabei baut das Betriebssystem selbst die für die Anpassung notwendige Software drum herum, indem die Typbibliothek des COM+ Objekts ausgelesen wird, um diesen Input für das Generieren einer in C# vorliegenden Web Services-Klasse zu nutzen. Und da im .NET Framework auch die Compiler enthalten sind, kann das Betriebssystem automatisch die Assembly-DLL kompilieren und in eine automatisch angelegte ASP.NET-Anwendung einbauen. Alles passiert transparent im Hintergrund, nach einigen Sekunden steht die Web Services-Anbindung zur Verfügung, ohne das der alte Sourcecode für das COM+-Objekt neu angefasst werden musste.

Der Delphi 7-Client
Angenommen, ein anderes Projektmitglied muss nun mit Delphi 7 einen Client für diesen Web Service entwickeln. Er braucht dazu nicht den Sourcecode des Web Services, sondern nur die Information, über welche URL dieser Web Service (genauer gesagt seine WSDL-Beschreibung) zu finden ist. In der Abbildung 5 sind die notwendigen Schritte zu sehen, die mit dem Experten für den WSDL-Import abgearbeitet werden. Als Verzeichnis für die WSDL-Quelle tippe ich in meinem Beispiel nur die URL http://192.168.10.1/DE2003/DE2003WS.dll/wsdl/IDE2003Service ein - den Rest macht der Delphi-Experte automatisch. Wie in der Abbildung 5 zu erkennen ist, konnte Delphi beim Importieren der WSDL-Informationen auch den Aufbau der Klasse TMyEmployee wiederherstellen, ohne einen Zugriff auf den originalen Sourcecode zu haben.


Abb. 5: Delphi generiert für den Client die Proxy-Klasse

Der WSDL-Importexperte hat die Unit IDE2003Service1.pas generiert - dort taucht die folgende globale Funktion auf, um eine Instanz des Web Services sofort anzufordern. Die Funktion nutzt zum einen optionale Vorgabewerte und greift immer dann auf die originale http-Adresse zu (nach Hause telefonieren), wenn beim Aufruf keine URL übergeben wird:

function GetIDE2003Service(
UseWSDL: Boolean=System.False;
Addr: string='';
HTTPRIO: THTTPRIO = nil): IDE2003Service;

Sie sehen - es ist nicht mehr notwendig, selbst zur THTTPRIO-Komponente (HTTP Remote Interface Object) zu greifen, um diese im Objektinspektor von Hand zu konfigurieren. Der Experte von Delphi 7 hat an dieser Stelle dazugelernt, sodass der Client sofort eine Instanz des Web Services anfordern und nutzen kann, wie das Beispiel in Listing 1 zeigt.


Listing 1

uses IDE2003Service1;
procedure TForm1.Button1Click(Sender: TObject);
var
aInput, aOutput: TMyEmployee;
aWS : IDE2003Service;
begin
// Schritt 1: Daten füllen
aInput := TMyEmployee.Create;
with aInput do begin
LastName := EditLastName.Text;
FirstName := EditFirstName.Text;
Salary := 0;
end;
// Schritt 2: Web Service aufrufen
aWS := GetIDE2003Service;
aOutput := aWS.echoMyEmployee(aInput);
// Schritt 3: Daten auswerten
ListboxLog.Items.Add(Format('LastName: %s; FirstName: %s',
[aOutput.LastName, aOutput.FirstName]));
end;


Allerdings taucht immer dann beim Aufruf ein Problem auf, wenn der Web Service nicht auf dem eigenen Rechner installiert ist und dort eine CPU vor sich hin werkelt, die auf der Höhe der Zeit (sprich schnell) ist. In meiner Testumgebung wird die Web Service-ISAPI-DLL auf einem Windows 2000 Server ausgeführt, der mit einem 1,6 GHz schnellen Pentium 4 und 512 MByte RDRAM bestückt ist. Das Problem und der Workaround dazu ist in der Abbildung 6 zu sehen - in der Projektdatei der ISAPI-DLL muss die Reihenfolge der Units ISAPIApp und ISAPIThreadPool ausgetauscht werden, damit der Spuk von willkürlichen Fehlermeldungen beim Aufruf des Web Services verschwindet.


Abb. 6: Ein Delphi 7-Bug und seine Auswirkung

Die .NET-Clients
Wenn nur ein Delphi 7-Client auf einen Delphi 7-Web Service zugreifen müsste, ist es den ganzen Aufwand nicht wert - denn in diesem Fall müssten wir gar nicht den Umweg über XML gehen. Ein Web Service macht nur dann Sinn, wenn beliebige Clients darauf zugreifen wollen oder wenn sich die Kommunikation durch das Firewall-Nadelöhr im Netzwerk (Port 80 für das HTTP-Protokoll) quälen muss. Auf der Profi-CD finden Sie daher auch Beispiele für .NET-Clients, wobei ich dafür unterschiedliche Ausführungsformen nutze:
  • Windows-Anwendung (in VB.NET geschrieben),
  • ASP.NET-Anwendung (in C# geschriebenes Web Form),
  • SmartDevice-Anwendung (in VB.NET geschriebene PocketPC-Anwendung).
Aus Platzgründen beschränke ich mich nur auf das Sourcecode-Beispiel für die in VB.NET geschriebene Windows-Anwendung. Wie dort zu erkennen ist, stellt auch die Entwicklungsumgebung Microsoft Visual Studio .NET 2002 einen Dialog bereit, der für den ausgewählten Web Service eine Proxy-Klasse automatisch generiert, sodass der Entwickler erst gar nicht mit den Niederungen von XML und SOAP in Berührung kommt. Wesentlich ist das Ergebnis - alle .NET-Anwendungen können direkt die vom Web Service geschickte Delphi-Klasse lesen und schreiben - an dieser Stelle spielt XML seinen Joker aus (Listing 2)


Listing 2

Private Sub ButtonEchoEmployee_Click( _ 
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles ButtonEchoEmployee.Click
Dim aWS As New WebReference1.IDE2003Serviceservice()
Dim aInput As New WebReference1.TMyEmployee()
With aInput
.LastName = TextBoxLastName.Text
.FirstName = TextBoxFirstName.Text
.Salary = 0
End With
Dim aOutput As WebReference1.TMyEmployee
aOutput = aWS.echoMyEmployee(aInput)
ListBox1.Items.Add(String.Format( _
"LastName: {0}; FirstName: {1}", _
aOutput.LastName, aOutput.FirstName))
StatusBar1.Text = "Web Service erfolgreich aufgerufen"
End Sub


Abb. 7: .NET kann die Delphi-Klasse lesen und schreiben

Um das Ganze noch zu toppen, zeigt die Abbildung 8 die Client-Anwendung für den PocketPC in Aktion, dieses Beispiel wurde allerdings mit dem brandneuen Microsoft Visual Studio .NET 2003 geschrieben. Auch hier unterscheidet sich die Vorgehensweise nicht von den anderen Clients, am rechten Rand der Abbildung 8 ist der Solution Explorer von Visual Studio .NET mit dem eingebundenen Verweis auf den Delphi 7-Web Service zu sehen. In der Voreinstellung verbirgt VS.NET in der Anzeige die automatisch generierte Proxy-Klasse, da der Entwickler dort nicht von Hand eingreifen muss.


Abb. 8: Der PocketPC-Client greift auf den Delphi 7 Web Service zu

Zum Abschluss sei mir noch der Hinweis gestattet, dass sich der Datenaustausch nicht nur auf Delphi-Klassen beschränkt. Selbstverständlich kann ein in .NET geschriebener Web Service ein gefülltes DataSet (Klasse aus ADO.NET) zurückliefern, das über eine XML-Transformation auch von einem Delphi-Client ausgewertet sowie im TDBGrid angezeigt und bearbeitet werden kann [3]. An dieser Stelle halten die Web Services ihre Versprechen ein, auch wenn man auf der Delphi-Seite stellenweise von Hand am Getriebe schrauben muss, weil der eine oder andere Bug sein Unwesen treibt.

Links und Literatur
  • [1] Der Entwickler: Objekte veröffentlichen 6/2002
  • [2] Der Entwickler: Dienstleister im Praxistest 3/2002
  • [3] Der Entwickler: Das Daten-Chamäleon 5/2002


    Hat Ihnen dieser Artikel gefallen? Dann abonnieren Sie das Entwickler Magazin direkt über unser Online-Formular.



zur vorherigen Seite
zurück
an den Anfang der Seite
nach oben
Diesen Artikel drucken
drucken
Diesen Artikel weiterempfehlen
empfehlen
Software & Support Verlag GmbH