Session D-WEB1 COM Server und WebServices in VFP und .NET Markus Winhard Sie wollen eine Internetanwendung als Ergänzung einer bestehenden VFP-Windowsanwendung integrieren. Das ist einer der wenigen Sektoren mit steigender Nachfrage. Um diese zu befriedigen können wir auf unser bestehendes Wissen zurückgreifen, müssen aber auch neue Technologien mit einbinden. Die von mir vorgestellten Lösungsvorschläge resultieren aus meiner eigenen Suche nach der passenden Technologie und Entwicklungsumgebung. Sie haben sich bereits in der Praxis bewährt. Zunächst war es mir wichtig, dass ich nicht das grundsätzliche Konzept meiner Anwendung ändern muss und bewährte und lieb gewonnene Funktionalitäten erhalten bleiben. Des Weiteren musste gewährleistet sein, dass mit den neuen „Hilfsmitteln“ meine Anwendung im Internet ähnlich performant und bedienerfreundlich ist wie in meiner Desktopanwendung. Für den Anwender sollte sich in der Bedienung möglichst wenig verändern. Dieser Vortrag liefert Ihnen das notwendige „Handwerkszeug“ um VFP und .Net gemeinsam zu verwenden. Was Sie außerdem noch brauchen, um eine zeitgemäße Internetanwendung zu erstellen, lernen Sie in meinem zweiten Vortrag Web-Frontends für VFP-Anwendungen. Sowohl diese Vortragsunterlagen als auch die zugehörigen Begleitdateien werden bis zur Konferenz sicherlich weiter verbessert werden. Die neueste Version können Sie hier herunterladen: http://www.bingo-ev.de/~mw368/devcon2006.html. Wenn Sie die Beispiele auf Ihrem Rechner testen wollen, stellen Sie sicher, daß die in den Abschnitten Deployment und Anlegen eines virtuellen Verzeichnisses dieses Dokuments genannten Voraussetzungen erfüllt sind. COM Server und WebServices in VFP und .NET © 2006 Markus Winhard (Gruppe WEB) 13. Visual FoxPro Entwicklerkonferenz 2006 D-WEB1 • 1 COM Server und WebServices in VFP Erstellen eines COM Servers in VFP Da wir auf die mit VFP gelieferte Datenbank “Northwind” zugreifen wollen, erstellen wir ein neues Projekt mit dem Namen “NorthwindData”. Sein Hauptprogramm ist ein PRG mit folgendem Aufbau: *=========================================================== * Hauptprogramm des COM-Servers/WebService NorthwindData. *=========================================================== DEFINE CLASS DataService AS Session OLEPUBLIC ENDDEFINE Der Name des PRGs ist beliebig. Kompilieren Sie das Projekt zu einem “Multi-threaded COM server (dll)”. Der neue COM Server wird automatisch unter Project > Project Info... > Servers eingetragen. 13. Visual FoxPro Entwicklerkonferenz 2006 2 • D-WEB1 (Gruppe WEB) COM Server und WebServices in VFP und .NET © 2006 Markus Winhard Wie Sie an dem Listbox-Titel “Server classes” sehen, könnte eine COM DLL auch mehrere COM Server enthalten. Hinzufügen von Methoden zum COM Server Damit unser neuer COM Server etwas nützt, braucht er Methoden. DEFINE CLASS DataService AS Session OLEPUBLIC #DEFINE ccNORTHWINDDATA "C:\Vfp9\Samples\Northwind\" PROCEDURE GetTable( tcTable AS String ) AS String LOCAL lcXML OPEN DATABASE (ccNORTHWINDDATA + "Northwind.dbc") SHARED USE (tcTable) SHARED lcXML = This.TableToXML( ALIAS() ) CLOSE DATABASES ALL RETURN lcXML ENDPROC PROTECTED PROCEDURE TableToXML LPARAMETERS tcAlias LOCAL lcXML CURSORTOXML( tcAlias, "lcXML" ) RETURN lcXML ENDPROC ENDDEFINE Methoden, die vom COM-Server veröffentlicht werden sollen, müssen in der “neueren” Schreibweise angelegt werden. D.h., wir verwenden runde Klammern statt LPARAMETERS, der Datentyp jedes Parameters muß angegeben werden und der Datentyp des Rückgabewerts muß angegeben werden. Methoden, die nach außen nicht sichtbar sein sollen, versehen wir mit dem Schlüsselwort PROTECTED. Ich habe mir angewöhnt, diese internen Methoden zur leichteren Unterscheidung in der “alten” Schreibweise anzulegen. Tatsächlich ist es aber egal, ob Sie bei internen Methode, die “alte” oder die “neuere” Schreibweise verwenden. COM Server und WebServices in VFP und .NET © 2006 Markus Winhard (Gruppe WEB) 13. Visual FoxPro Entwicklerkonferenz 2006 D-WEB1 • 3 Es ist, wie in VFP üblich, egal, ob Sie Ihre Methoden als PROCEDURE oder FUNCTION anlegen. Testen des COM Servers Zuerst sollten wir testen, ob unsere Klasse DataService in VFP funktioniert, ohne den Umweg über die COMSchnittstelle. Dazu fügen wir zu Beginn des Hauptprogramms folgenden Code ein: * Test als VFP-Klasse. LOCAL loDS loDS = CREATEOBJECT( "DataService" ) ACTIVATE SCREEN CLEAR SET MEMOWIDTH TO 100 ? loDS.GetTable( "Region" ) In Ihrem VFP-Hauptfenster sollte jetzt die Tabelle “Region” als XML angezeigt werden. <?xml version = "1.0" encoding="Windows-1252" standalone="yes"?> <VFPData> <region> <regionid>1</regionid> <regiondescription>Eastern</regiondescription> </region> <region> <regionid>2</regionid> <regiondescription>Western</regiondescription> </region> <region> <regionid>3</regionid> <regiondescription>Northern</regiondescription> </region> <region> <regionid>4</regionid> <regiondescription>Southern</regiondescription> </region> </VFPData> Damit die neuen Methoden auch in der COM Server DLL enthalten sind, müssen wir das Projekt erneut kompilieren. Danach können wir den COM Server testen. Da zur Laufzeit nur der COM Server instantiiert, aber nicht das Hauptprogramm ausgeführt wird, kann auch dieser Code problemlos zu Beginn des Hauptprogramms unseres COM Servers eingefügt werden. Nachdem der COM Server beim Kompilieren registriert wurde, kann Intellisense auf seine Methoden-Signaturen zugreifen. 13. Visual FoxPro Entwicklerkonferenz 2006 4 • D-WEB1 (Gruppe WEB) COM Server und WebServices in VFP und .NET © 2006 Markus Winhard Ein WebService für unseren COM Server Ein VFP-WebService ist eigentlich nur eine Hülle um einen VFP-COM Server. Um unseren COM Server zu einem WebService zu machen, lassen wir das COM Server Projekt geöffnet und rufen den Web Services Wizard auf. COM Server und WebServices in VFP und .NET © 2006 Markus Winhard (Gruppe WEB) 13. Visual FoxPro Entwicklerkonferenz 2006 D-WEB1 • 5 Die Auswahl Automatically generate XML web service files during project build ist wichtig. Sie bewirkt, daß dem Projekt ein Project Hook hinzugefügt wird, der vor dem Kompilieren dafür sorgt, daß der Webserver die COM Server DLL freigibt. Ohne diesen Project Hook müßten Sie den Webservice jedesmal vor dem Kompilieren manuell beenden oder VFP würde die Fehlermeldung anzeigen, daß die COM Server DLL nicht überschrieben werden kann, solange sie ein anderer Prozess im Zugriff hat. Vergewissern Sie sich unbedingt, daß alle öffentlichen COM Server Methoden, die Sie auch im WebService veröffentlichen wollen, im Tabreiter “Methods” der [Advanced...] Dialogs ein Häkchen haben. Das ist eine 13. Visual FoxPro Entwicklerkonferenz 2006 6 • D-WEB1 (Gruppe WEB) COM Server und WebServices in VFP und .NET © 2006 Markus Winhard beliebte Stolperfalle. Vor allem wenn man später einmal dem COM Server neue Methoden hinzufügt, muß man den neuen Methoden in diesem Dialog ein Häkchen geben. Nach einem Klick auf die Schaltfäche [Generate...] sollte folgende Meldung erscheinen: Schließen Sie anschließend das COM Server Projekt und öffnen Sie es erneut, damit der Project Hook aktiv werden kann. COM Server und WebServices in VFP und .NET © 2006 Markus Winhard (Gruppe WEB) 13. Visual FoxPro Entwicklerkonferenz 2006 D-WEB1 • 7 WebService in VFP testen Auch diesen Testcode können wir wieder zu Beginn des Hauptprogramms unseres COM Server Projekts einfügen. Durch Eingabe des Kürzels ws zeigt uns Intellisense einen Dialog, in dem wir den gewünschten WebService auswählen können. Anschließend stehen die Methoden des WebService in Intellisense zur Verfügung. Ebenso die Methodensignaturen: Reports Der REPORT FORM Befehl wird in COM Server DLLs nicht unterstützt, er funktioniert nur in EXE COM Servern. Das heißt, wir müssen alle Druckroutinen in einen separate COM Server EXE packen. Wenn nun aus einer COM Server DLL (oder aus einem WebService) gedruckt werden soll, dann müssen wir in einer Methode der COM Server DLL mit CREATEOBJECT() die COM Server EXE instantiieren und eine Methode aufrufen, die das Drucken übernimmt. VFP COM Server und WebServices aus .Net-Anwendungen aufrufen Grundsätzlich ist es egal, welche Art von .Net Anwendung wir dazu verwenden (ASP.Net-Anwendung, .NetWindowsanwendung, .Net-WebService, .Net-Konsolenanwendung), der .Net-Code ist immer derselbe. Da dieser Vortrag die Grundlagen für meinen anderen Vortrag Web-Frontends für VFP-Anwendungen vermitteln soll, verwende ich auch hier eine kleine ASP.Net-Anwendung. ASP.Net Solution anlegen Die Organisationseinheit für ein Programm in Visual Studio 2005 ist eine Solution. Eine Solution enthält mindestens ein Projekt, kann aber auch mehrere Projekte enthalten. 13. Visual FoxPro Entwicklerkonferenz 2006 8 • D-WEB1 (Gruppe WEB) COM Server und WebServices in VFP und .NET © 2006 Markus Winhard COM Server und WebServices in VFP und .NET © 2006 Markus Winhard (Gruppe WEB) 13. Visual FoxPro Entwicklerkonferenz 2006 D-WEB1 • 9 Wir erhalten eine neue Solution, die lediglich eine leere WebForm Default.aspx enthält. In der Solution wird unterhalb der Default.aspx eine weitere Datei Default.apsx.cs angezeigt. Sie enthält den Quellcode der Webseite. 13. Visual FoxPro Entwicklerkonferenz 2006 10 • D-WEB1 (Gruppe WEB) COM Server und WebServices in VFP und .NET © 2006 Markus Winhard COM Server und WebServices in VFP und .NET © 2006 Markus Winhard (Gruppe WEB) 13. Visual FoxPro Entwicklerkonferenz 2006 D-WEB1 • 11 VFP COM Server einbinden Damit wir einen COM Server in einer .Net Solution aufrufen können, müssen wir die Solution zuerst mit dem COM Server bekannt machen. Das ist notwendig, weil .Net COM Server nicht direkt aufruft, sondern um jeden COM Server eine Hülle aus .Net Code baut. Rufen Sie dazu im Kontextmenü der Solution den Punkt Add Reference auf. 13. Visual FoxPro Entwicklerkonferenz 2006 12 • D-WEB1 (Gruppe WEB) COM Server und WebServices in VFP und .NET © 2006 Markus Winhard Im folgenden Dialog wechseln wir auf den Tabreiter COM und wählen die NorthwindData Type Library. COM Server und WebServices in VFP und .NET © 2006 Markus Winhard (Gruppe WEB) 13. Visual FoxPro Entwicklerkonferenz 2006 D-WEB1 • 13 Dabei erzeugt .Net die erwähnte Hülle um unseren COM Server als Interop.northwinddata.dll. Beim Aufrufen der Methoden des COM Servers hilft uns Intellisense, wie wir es von VFP gewohnt sind. 13. Visual FoxPro Entwicklerkonferenz 2006 14 • D-WEB1 (Gruppe WEB) COM Server und WebServices in VFP und .NET © 2006 Markus Winhard COM Server und WebServices in VFP und .NET © 2006 Markus Winhard (Gruppe WEB) 13. Visual FoxPro Entwicklerkonferenz 2006 D-WEB1 • 15 Mit dem folgenden Code holen wir den Inhalt der Tabelle Region der Northwind-Datenbank als XML und geben das XML auf der Webseite aus. protected void Page_Load(object sender, EventArgs e) { // COM Server instantiieren. northwinddata.DataService loCOMServer = new northwinddata.DataService(); // Methode aufrufen. string lcXML = loCOMServer.GetTable("Region"); // XML auf der Webseite ausgeben. Response.Write(lcXML); Response.End(); } Mit der Funktionstaste F5 starten wir die Webseite im Browser um das Ergebnis anzuzeigen. Beim ersten Aufruf erscheint folgender Dialog, den wir mit [OK] bestätigen. 13. Visual FoxPro Entwicklerkonferenz 2006 16 • D-WEB1 (Gruppe WEB) COM Server und WebServices in VFP und .NET © 2006 Markus Winhard Aufruf des Codes aus dem Click() eines Buttons Da wir die WebForm Default.aspx im Laufe dieses Vortrags noch für weitere Beispiele verwenden werden, verlagern wir den Code in einen Button.Dazu ziehen wir aus der Toolbox-Rubrik Standard einen Button auf die WebForm. Die Caption das Buttons steht bei ASP.Net im Property Text. Wir setzen bei dem neuen Button den Text COM Server aufrufen. Falls Sie das Name-Property suchen, das heißt in ASP.Net ID. COM Server und WebServices in VFP und .NET © 2006 Markus Winhard (Gruppe WEB) 13. Visual FoxPro Entwicklerkonferenz 2006 D-WEB1 • 17 Wenn Sie die Toolbox aus Platzgründen lieber nicht immer im Vordergrund haben wollen, dann aktivieren Sie im Kontextmenü der Toolbox-Titelleiste den Modus Auto Hide. Per Doppelklick auf den Button gelangen Sie wie in VFP in dern Code-Editor. Dabei wurde automatisch eine Methode cmdCOMServer_Click() in der WebForm angelegt. Damit ASP.Net weiß, wann diese Methode aufgerufen werden soll, wurde zusätzlich dem HTML des Buttons das Attribut OnClick="cmdCOMServer_Click" hinzugefügt. Tatsächlich wird hier zum Zeitpunkt des Kompilierens eine Art verstecktes BINDEVENTS() eingebaut, aber diese Details gehen über den Umfang dieses Vortrags hinaus. Nachdem wir den Code aus der Methode Page_Load() in die Methode cmdCOMServer_Click() verschoben haben, sieht unsere WebForm-Klasse so aus: public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } protected void cmdCOMServer_Click(object sender, EventArgs e) { // COM Server instantiieren. northwinddata.DataService loCOMServer = new northwinddata.DataService(); // Methode aufrufen. string lcXML = loCOMServer.GetTable("Region"); 13. Visual FoxPro Entwicklerkonferenz 2006 18 • D-WEB1 (Gruppe WEB) COM Server und WebServices in VFP und .NET © 2006 Markus Winhard // XML auf der Webseite ausgeben. Response.Write(lcXML); Response.End(); } } Variablen und Datentypen in .Net Wenn Sie bisher noch nie Kontakt mit der Programmierung in einer .Net-Sprache hatten, dann werden Sie sich sicherlich fragen, welche Bedeutung die einzelnen Teile der Zeile northwinddata.DataService loCOMServer = new northwinddata.DataService(); haben. Zum leichteren Verständnis spalten wir diese Zeile in zwei Zeilen auf: northwinddata.DataService loCOMServer; loCOMServer = new northwinddata.DataService(); In VFP würde man das so schreiben: LOCAL loCOMServer AS northwinddata.DataService loCOMServer = NEWOBJECT("northwinddata.DataService") Allerdings geht .Net noch einen Schritt weiter als VFP. Man muß in :Net keinen COM Server bauen um einer Variable diese Klasse als Datentyp zuzuweisen. Das klappt auch mit jeder Klasse aus der aktuellen Solution und mit allen Klassen des .Net Frameworks. Im Gegensatz zu VFP ist die Angabe des Datentyps aber nicht nur für Intellisense wichtig, sondern auch für den Kompiler. Ein .Net Kompiler versucht viele Fehler im Quellcode bereits beim Kompilieren zu erkennen, die VFP erst zur Laufzeit bemerkt. So kann der Kompiler z.B. prüfen, ob ein Property oder eine Methode wirklich Bestandteil der verwendeten Klasse ist. Damit das funktioniert, muß der Kompiler aber wissen, daß wir in der Variable loCOMServer eine Instanz der Klasse northwinddata.DataService speichern wollen. Und das wiederum ist der Grund dafür, daß wir northwinddata.DataService als Datentyp der Variable loCOMServer angeben müssen. Und weil in.Net alles ein Objekt ist, ist dieses Konzept universell anwendbar. D.h., selbst so einfache Datentypen wie String oder Integer sind eigentlich Instanzen der Klasse string bzw. int. und damit gelten dieselben Regeln. VFP WebService einbinden Ziehen Sie einen zweiten Button aus der Toolbox auf die WebForm und setzen Sie sein Property Text=”WebService aufrufen”. COM Server und WebServices in VFP und .NET © 2006 Markus Winhard (Gruppe WEB) 13. Visual FoxPro Entwicklerkonferenz 2006 D-WEB1 • 19 Damit wir einen WebService in einer .Net Solution aufrufen können, müssen wir wie beim COM Server die Solution zuerst mit dem WebService bekannt machen. Auch hier baut .Net eine Hülle aus .Net Code um den WebService. Rufen Sie dazu im Kontextmenü der Solution den Punkt Add Web Reference auf. 13. Visual FoxPro Entwicklerkonferenz 2006 20 • D-WEB1 (Gruppe WEB) COM Server und WebServices in VFP und .NET © 2006 Markus Winhard Im folgenden Dialog rufen Sie die URL Ihres VFP-WebService auf und vergeben in der Textbox Web reference name einen sinnvollen Namen für den WebService. COM Server und WebServices in VFP und .NET © 2006 Markus Winhard (Gruppe WEB) 13. Visual FoxPro Entwicklerkonferenz 2006 D-WEB1 • 21 Nach dem Hinzufügen des WebService zu unserer Solution können wir per Doppelklick die neue WebFormMethode cmdWebService_Click() erstellen und folgenden Code einfügen. Wie in VFP unterstützt uns auch hierbei Intellisense. protected void cmdWebService_Click(object sender, EventArgs e) { // WebService instantiieren. NorthwindWebService.DataService loWS = new NorthwindWebService.DataService(); // Methode aufrufen. string lcXML = loWS.GetTable("Region"); // XML auf der Webseite ausgeben. Response.Write(lcXML); Response.End(); } Sie werden beim ersten Aufruf des VFP WebService wahrscheinlich eine relativ lange Verzögerung bemerken. Diese Verzögerung hat ihre Ursache darin, daß der WebServer unseren WebService aufgrund eines Timeouts zwischenzeitlich entladen hat. Ab dem zweiten Aufruf werden Sie aber keinen Unterschied zum Aufruf eines COM Servers mehr spüren. Um ganz sicherzugehen, werde wir das auch nachmessen. Aber dazu später mehr. Da unser VFP WebService nur eine Hülle um unseren VFP COM Server ist, ist auch das auf der Webseite angezeigte XML identisch. 13. Visual FoxPro Entwicklerkonferenz 2006 22 • D-WEB1 (Gruppe WEB) COM Server und WebServices in VFP und .NET © 2006 Markus Winhard Das VFP Toolkit 2.0 für .Net 2.0 Bereits im Jahre 2002 haben sich ein paar findige VFP-Programmierer mit .Net beschäftigt. Um schneller produktiv zu werden, wollten Sie die von VFP bekannten Funktionen auch in .Net verwenden. Also haben sie eine Funktionssammlung geschrieben, die ca 200 der wichtigsten VFP-Funktionen in .Net nachbildet. Diese Funktionssammlung liegt seitdem auf diversen Servern im Internet unverändert zum Download. Sie kann im Prinzip unverändert in .Net 2.0 verwendet werden. Allerdings bietet uns .Net 2.0 mit den „Partial Classes“ die Möglichkeit, Code aus mehreren Quellcode-Dateien zu einer Klasse zusammenzufassen. Das hat in diesem Fall den Vorteil, daß man nicht mehr wissen muß, in welcher der 10 Klassen eine VFP-Funktion zu finden ist. Es gibt nur noch eine einzige Klasse „VFP“, die alle Funktionen enthält. Ich habe das VFP Toolkit für .Net entsprechend umgeschrieben, die Dokumentation angepaßt und die Versionsnummer 2.0 vergeben. Sie finden das VFP Toolkit 2.0 für .Net 2.0 in den Begleitdateien dieses Vortrags. Hinzufügen von VFP-Funktionen zur Solution Im Kontextmenü der Solution den Punkt „Add Reference...“ auswählen. Im Tabreiter „Browse“ die VFPToolkitNET.dll aus den Begleitdateien dieses Vortrags auswählen. COM Server und WebServices in VFP und .NET © 2006 Markus Winhard (Gruppe WEB) 13. Visual FoxPro Entwicklerkonferenz 2006 D-WEB1 • 23 Damit die Methoden einer Klasse aus einer .Net-DLL im Quellcode einfach verwendet werden können müssen wir in unseren Quellcode eine entsprechende „using“-Direktive zu Beginn der Quellcode-Datei (*.cs) aufnehmen. Das entspricht in etwa einem SET CLASSLIB TO in VFP. Mehr dazu im nächsten Abschnitt. Ein einfacher Performance-Test Da wir uns nun jede Menge bekannte VFP-Funktionen in .Net zur Verfügung stehen, wollen wir das doch gleich einmal ausprobieren. Lassen Sie uns die Zeit nehmen die es dauert, den COM Server bzw. den WebService zu instantiieren und seine Methode GetType() aufzurufen. Und weil wir schon dabei sind, rechnen wir auch die Zeit zum Freigeben der externen Resource “WebService” dazu. Das Freigeben von externen Resourcen sollte laut .Net-Doktrin in einer Methode namens Dispose() passieren. Für uns heißt das, daß wir als brave Programmierer bei jedem Objekt, das eine Methode Dispose() hat, diese Methode aufrufen, sobald das Objekt nicht mehr benötigt wird. So sieht unser neuer Quellcode aus: // SET CLASSLIB TO... using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; // VFP-Funktionen einbinden. using VFPToolkit; public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { 13. Visual FoxPro Entwicklerkonferenz 2006 24 • D-WEB1 (Gruppe WEB) COM Server und WebServices in VFP und .NET © 2006 Markus Winhard } protected void cmdCOMServer_Click(object sender, EventArgs e) { // Zeit nehmen. double lnSeconds0 = Vfp.Seconds(); // COM Server instantiieren. northwinddata.DataService loCOMServer = new northwinddata.DataService(); // Methode aufrufen. string lcXML = loCOMServer.GetTable("Region"); // Nochmal Zeit nehmen. double lnSeconds1 = Vfp.Seconds(); // XML und Dauer auf der Webseite ausgeben. Response.Write("<?Dauer = " + (lnSeconds1 - lnSeconds0) + " ?>"); Response.Write(lcXML); Response.End(); } protected void cmdWebService_Click(object sender, EventArgs e) { // Zeit nehmen. double lnSeconds0 = Vfp.Seconds(); // WebService instantiieren. NorthwindWebService.DataService loWS = new NorthwindWebService.DataService(); // Methode aufrufen. string lcXML = loWS.GetTable("Region"); // .Net auffordern, die vom WebService-Proxy // belegten Resourcen freizugeben. loWS.Dispose(); // Nochmal Zeit nehmen. double lnSeconds1 = Vfp.Seconds(); // XML und Dauer auf der Webseite ausgeben. Response.Write("<?Dauer = " + (lnSeconds1 - lnSeconds0) + " ?>"); Response.Write(lcXML); Response.End(); } } Und hier kommt das Ergebnis. Das Einfassen der Dauer mit “<?” und “?>” ist notwendig, da wir im Anschluß XML-Daten ausgeben. Ohne diese Begrenzer würde der Internet Explorer das Ganze nicht mehr als gültiges XML akzeptieren und eine Fehlermeldung anzeigen. COM Server und WebServices in VFP und .NET © 2006 Markus Winhard (Gruppe WEB) 13. Visual FoxPro Entwicklerkonferenz 2006 D-WEB1 • 25 Sowohl der COM Server als auch der WebService hatten Laufzeiten zwischen “nicht meßbar” und 0,3 Sekunden. Wie Sie sehen ist es in unserer Testumgebung für die Performance unerheblich, ob wir unseren VFP-Code als COM Server oder WebService aufrufen. Nach Aussage anderer Programmierer, die bereits mehrere Projekte mit Net und COM Servern bzw. WebServices durchgeführt haben, hat es sich in der Praxis durchgesetzt, auf Webseiten aus Gründen der Sicherheit und der Skalierbarkeit bevorzugt WebServices zu verwenden. Im Windows-Desktop-Bereich fällt die Entscheidung meist zugunsten der COM Server, da man nicht voraussetzen kann, daß immer ein lokaler Webserver installiert ist. Übergabe von komplexen Parametern Um es gleich vorwegzunehmen: In einer Anwendung, die in mehr als einer Programmiersprache erstellt wird, sollte man sich beim Austausch von Daten zwischen den beiden Sprachen am kleinsten gemeinsamen Nenner orientieren. Alles andere führt nur zu erhöhtem Aufwand und damit zu erhöhten Kosten. In einer idealen Welt werden die Schnittstellen zwischen den beteiligten Sprachen bereits vor Beginn des eigentlichen Projekts festgelegt. In der Regel wird man komplexe Daten als XML austauschen. Das XML-Format wurde extra für diesen Zweck geschaffen und eignet sich in der Praxis tatsächlich hervorragend für diesen Einsatzzweck. VFP und .Net können Daten im XML-Format sehr gut in das jeweils benötigte Format konvertieren. XML kann problemlos nicht nur mit COM-Servern, sondern auch mit WebServices ausgetauscht werden. Binäre Formate oder komplexe Objekte können meist nicht mit WebServices ausgetauscht werden. 13. Visual FoxPro Entwicklerkonferenz 2006 26 • D-WEB1 (Gruppe WEB) COM Server und WebServices in VFP und .NET © 2006 Markus Winhard Wenn Sie meinen zweiten Vortrag Web-Frontends für VFP-Anwendungen ebenfalls besuchen, dann werden Sie sehen, daß die Übergabe jeglicher Form von Daten per XML nicht nur leicht zu handhaben ist, sondern auch noch performant ist. Lassen Sie mich als Beispiel zwei Funktionen aus dem dotNetHelper.prg zeigen, das den Begleitdateien zu diesem Vortrag beiliegt. Die erste Funktion XMLFromCursors () wird gerne verwendet um alle Daten, die in einer .Net Windows Form oder ASP.Net WebForm benötigt werden, in ein einziges XML zu verpacken. *-------------------------------------------* Alle übergebenen Cursor in .Net DataSet * kompatibles XML packen. *-------------------------------------------FUNCTION XMLFromCursors LPARAMETERS tcAliases *-------------------------------------------* Setup. *-------------------------------------------LOCAL i, lcXML, loXMLAdapter AS XMLAdapter, ; lnSelect, lcAlias, lnRecno lnSelect = SELECT(0) *-------------------------------------------* XMLAdapter erstellen. *-------------------------------------------loXMLAdapter = CREATEOBJECT( "XMLAdapter" ) loXMLAdapter.UTF8Encoded = .T. && Default in .Net. *-------------------------------------------* Alle übergebenen Aliase in den XMLAdapter * aufnehmen. Dabei sicherstellen, daß die * Satzzeiger wiederhergestellt werden. *-------------------------------------------FOR i = 1 TO GETWORDCOUNT( m.tcAliases, "," ) lcAlias = GETWORDNUM( m.tcAliases, i, "," ) SELECT (m.lcAlias) lnRecno = RECNO() m.loXMLAdapter.AddTableSchema( m.lcAlias ) SELECT (m.lcAlias) LOCATE RECORD (m.lnRecno) ENDFOR *-------------------------------------------* XML ausgeben. *-------------------------------------------m.loXMLAdapter.ToXML( "lcXML" ) *-------------------------------------------* Cleanup. *-------------------------------------------loXMLAdapter = .NULL. RELEASE loXMLAdapter SELECT (m.lnSelect) * RETURN m.lcXML ENDFUNC Die zweite Funktion, ChangesFromDiffGram() verwendet man, um ein XML-DiffGram einzulesen. Ein XMLDiffGram enthält alle Änderungen, die die .Net-Anwendung an unseren Daten vorgenommen hat inklusive Buffering (aktueller Wert / Wert vor der Änderung). Mit Hilfe der Klassen XMLAdapter und CursorAdapter können diese Änderungen performant auf eine gepufferte Tabelle oder View übertragen werden. ChangesFromDiffGram() ist so implementiert, daß es möglich ist, Update-Konflikte zu erkennen. Somit können wir bei Bedarf darauf reagieren, wenn ein anderer User die Daten, die wir gerade speichern wollen, zwischenzeitlich verändert hat. Es ist zwar grundsätzlich möglich, Änderungen für mehrere Tabellen gleichzeitig zu übertragen. Zugunsten besserer Lesbarkeit verzichtet der Code in ChangesFromDiffGram() aber auf diese Möglichkeit. COM Server und WebServices in VFP und .NET © 2006 Markus Winhard (Gruppe WEB) 13. Visual FoxPro Entwicklerkonferenz 2006 D-WEB1 • 27 *-------------------------------------------* Änderungen aus XML-DiffGram auf gepufferten * Cursor übertragen. Das DiffGram muß ein * Schema enthalten. Der Code geht davon aus, * daß das DiffGram nur Schema und Änderungen * für eine einzige Tabelle/View enthält. *(..)Der Ersatz für die fehlerhafte *(..)Funktion ApplyDiffGram(). *-------------------------------------------FUNCTION ChangesFromDiffGram LPARAMETERS tcDiffGram, tcAlias, tcKeyFieldList, ; tlForce, taErrorRecordNumbers *-------------------------------------------* Setup. *-------------------------------------------LOCAL lnSelect, lnRecno, loXMLAdapter AS XMLAdapter, ; lcUpdatableFieldList, lcUpdateNameList, ; loCursorAdapter AS CursorAdapter, i, lcFldState, ; lcDiffGramAlias, lcField, llSuccess lcDiffGramAlias = m.tcAlias + "_XML" llSuccess = .F. lnSelect = SELECT(0) lnRecno = RECNO( m.tcAlias ) SELECT 0 *-------------------------------------------* DiffGram in temp. Cursor wandeln. *-------------------------------------------loXMLAdapter = CREATEOBJECT( "XMLAdapter" ) WITH loXMLAdapter .LoadXML( m.tcDiffGram ) .Tables[ 1 ].Alias = m.lcDiffGramAlias .Tables[ 1 ].ChangesToCursor() ENDWITH *-------------------------------------------* Felder, die keine Änderung im Wert * aufweisen, auf "nicht geändert" setzen. *(..)Leider führt der XMLAdapter immer für *(..)*alle* Felder einen REPLACE durch, statt *(..)nur für die Felder, die im DiffGram *(..)unterschiedliche Werte haben. *-------------------------------------------SELECT (m.lcDiffGramAlias) SCAN lcFldState = GETFLDSTATE(-1) *-------------------------------------------* Nur geänderte Sätze prüfen. Neu angelegte * und gelöschte Sätze nicht prüfen. *-------------------------------------------IF LEFT( m.lcFldState, 1 ) == "1" && Geänderter Satz. FOR i = 1 TO LEN( m.lcFldState ) - 1 lcField = FIELD(i) IF SUBSTR( m.lcFldState, i + 1, 1 ) == "2" ; AND EVALUATE( m.lcField ) == OLDVAL( m.lcField ) SETFLDSTATE( i, 1 ) ENDIF ENDFOR ENDIF ENDSCAN *-------------------------------------------* CursorAdapter an den DiffGram-Cursor binden * um die gänderten Felder des * DiffGram-Cursors in die Basistabelle/-view * zu übertragen. Das funktioniert wie eine * View auf eine View. *-------------------------------------------loCursorAdapter = CREATEOBJECT( "CursorAdapter" ) WITH loCursorAdapter .BreakOnError = .T. 13. Visual FoxPro Entwicklerkonferenz 2006 28 • D-WEB1 (Gruppe WEB) COM Server und WebServices in VFP und .NET © 2006 Markus Winhard .Alias = m.lcDiffGramAlias .BufferModeOverride = 5 .DataSourceType = "NATIVE" .WhereType = IIF( m.tlForce, 1, 3 ) .ConflictCheckType = IIF( m.tlForce, 2, 3 ) .Tables = m.tcAlias .SelectCmd = "SELECT * FROM " + m.tcAlias .KeyFieldList = m.tcKeyFieldList *-------------------------------------------* Alle Felder des DiffGram-Cursors * aktualisierbar machen, für die in der * Basistabelle/-view ein gleichnamiges Feld * existiert. *-------------------------------------------lcUpdatableFieldList = "" lcUpdateNameList = "" AFIELDS( laFields, m.tcAlias ) tcAlias = LOWER( m.tcAlias ) FOR i = 1 TO AFIELDS( laFields_XML, m.lcDiffGramAlias ) *-------------------------------------------* Gibts das Feld auch in der * Basistabelle/-view? *-------------------------------------------IF ASCAN( laFields, laFields_XML[ i, 1 ], 1, -1, 1, 1+2 ) > 0 lcField = LOWER( laFields_XML[ i, 1 ] ) lcUpdatableFieldList = m.lcUpdatableFieldList +","+ ; m.lcField lcUpdateNameList = m.lcUpdateNameList +","+ ; m.lcField +" "+ m.tcAlias +"."+ m.lcField ENDIF ENDFOR .UpdatableFieldList = SUBSTR( m.lcUpdatableFieldList, 2 ) .UpdateNameList = SUBSTR( m.lcUpdateNameList, 2 ) *-------------------------------------------* DiffGram-Cursor an den CursorAdapter * binden. *-------------------------------------------.CursorAttach() ENDWITH *-------------------------------------------* Änderungen aus dem DiffGram-Cursor in die * Basistabelle/-view übertragen. *-------------------------------------------llSuccess = TABLEUPDATE( 2, m.tlForce, ; m.lcDiffGramAlias, taErrorRecordNumbers ) *-------------------------------------------* Cleanup. *(..)Der DiffGram-Cursor wird beim Freigeben *(..)des CursorAdapters automatisch *(..)geschlossen. *-------------------------------------------loXMLAdapter = .NULL. loCursorAdapter = .NULL. RELEASE loXMLAdapter, loCursorAdapter SELECT (m.tcAlias) LOCATE RECORD (m.lnRecno) SELECT (m.lnSelect) * RETURN m.llSuccess ENDFUNC Wenn die .Net-Abteilung schneller war, dann kann es Ihnen passieren, daß Sie als VFP-Programmierer Schnittstellen bedienen müssen, wie man sie in der .Net Welt gerne zwischen Servern und Clients verwendet. Dort werden Daten meist in Form von DataSets COM Server und WebServices in VFP und .NET © 2006 Markus Winhard (Gruppe WEB) 13. Visual FoxPro Entwicklerkonferenz 2006 D-WEB1 • 29 verschickt. Ein DataSet ist am ehesten vergleichbar mit der VFP-Klasse Dataenvironment. D.h., ein DataSet kann mehrere gepufferte Tabellen enthalten. Daneben kann es auch Relationen, Indizes und Filter enthalten. Tatsächlich wandelt .Net ein DataSet bei bestimmten Transportmedien selbstständig ins XML-Format und wieder zurück (das bekannteste Beispiel dafür sind SOAP-kompatible WebServices), aber davon merkt der .NetProgrammierer nichts. Damit Sie als VFP-Programmierer auch nicht viel davon merken, habe ich die folgenden beiden Funktionen ins dotNetHelper.prg aufgenommen. *-------------------------------------------* dotNet DataSet in XML wandeln. *(..)Bisher nur mit SOAP3-WebService *(..)getestet. *-------------------------------------------FUNCTION DataSetToXML LPARAMETERS toDataSetDocument *-------------------------------------------* Setup. *-------------------------------------------LOCAL lcXML, loXMLAdapter AS XMLAdapter *-------------------------------------------* DataSets als XML ausgeben. *-------------------------------------------#IF .T. *-------------------------------------------* Entweder so... *-------------------------------------------lcXML = m.toDataSetDocument.item[0].parentNode.Xml #ELSE *-------------------------------------------* ...oder so. *-------------------------------------------loXMLAdapter = CREATEOBJECT( "XMLAdapter" ) m.loXMLAdapter.Attach( m.toDataSetDocument ) m.loXMLAdapter.ToXML( "lcXML" ) #ENDIF *-------------------------------------------* Cleanup. *-------------------------------------------toDataSetDocument = .NULL. loXMLAdapter = .NULL. RELEASE toDataSetDocument, loXMLAdapter * RETURN m.lcXML ENDFUNC *-------------------------------------------* dotNet DataSet aus XML erzeugen. *(..)Bisher nur mit SOAP3-WebService *(..)getestet. *-------------------------------------------FUNCTION XMLToDataSet LPARAMETERS tcXML *-------------------------------------------* Setup. *-------------------------------------------LOCAL loDOM, loDataSetDocument loDOM = CREATEOBJECT( "MSXML2.DomDocument" ) *-------------------------------------------* XML einlesen und als DataSet ausgeben. *-------------------------------------------m.loDOM.LoadXML( m.tcXML ) loDataSetDocument = m.loDOM.DocumentElement.ChildNodes() *-------------------------------------------* Cleanup. *-------------------------------------------13. Visual FoxPro Entwicklerkonferenz 2006 30 • D-WEB1 (Gruppe WEB) COM Server und WebServices in VFP und .NET © 2006 Markus Winhard loDOM = .NULL. RELEASE loDOM * RETURN m.loDataSetDocument ENDFUNC Debuggen von VFP COM Servern Zu diesem Thema gibt es zwei verschiedene Ansätze. Den ersten von Maurice de Beijer finden Sie unter http://www.theproblemsolver.nl/aspdevelopmentanddebugging/index.htm. Er verwendet die Active Accessibility API. Der zweite Ansatz ist von Rick Strahl und eignet sich besonders zum Debuggen von VFP COM Servern, die aus.Net aufgerufen werden. Hier wird es erklärt: http://west-wind.com/WebLog/posts/666.aspx. Es ist gut zu wissen,. daß man die Möglichkeit hat, einen VFP COM Server zu debuggen, falls nötig. Allerdings findet man nach meiner Erfahrung 99 Prozent der auftretenden Fehler wesentlich schneller, wenn man es so macht, wie zu Anfang dieses Vortrags unter der Überschrift Testen des COM Servers erklärt. Da jeder VFP COM Server im Inneren aus einer VFP-Klasse besteht, kann man diese Klasse auch direkt in der VFP Entwicklungsumgebung (ohne den Umweg über COM) instantiieren und ihre Methoden aufrufen. Protokollieren der Aufrufparameter Wenn Sie einen Fehlerfall in einem COM Server erst nach der Auslieferung feststellen, dann ist es interessant, die exakten Eingabeparameter zur Verfügung zu haben, die zum Fehler führten. Diese Daten sind auch hilfreich, wenn Sie nach Änderungen an einer Methode Unit-Tests durchführen wollen. Da Ihnen jede Menge Eingabeparameter und zugehörige Rückgabewerte zur Verfügung stehen, können Sie testen, ob Ihre Methode sich nach außen noch genauso verhält wie vor der Änderung. *=========================================================== * Protokollierung der eingehenden Anfragen und der * ausgehenden Antworten eines COM Service oder WebServers. *=========================================================== DEFINE CLASS Protokoll AS Session OLEPUBLIC *-------------------------------------------* Name extra zuweisen, sonst bleibt er bei * COM Servern leer. *-------------------------------------------Name = "Protokoll" PROTECTED cLogFile cLogFile = "" PROCEDURE GetData( tnID AS Integer ) AS String LOCAL lcData lcData = "Hallo Welt" RETURN This.LogIt( lcData ) ENDPROC PROCEDURE Init *-------------------------------------------* Hier die Methode LogIt an alle öffentlichen * Methoden des COM Servers binden. *-------------------------------------------BINDEVENT( This, "GetData", This, "LogIt" ) *... *-------------------------------------------* Pfad der Logdatei. COM Server und WebServices in VFP und .NET © 2006 Markus Winhard (Gruppe WEB) 13. Visual FoxPro Entwicklerkonferenz 2006 D-WEB1 • 31 *-------------------------------------------This.cLogFile = FORCEEXT( IIF( VERSION(2) == 2, ; FULLPATH( ".\" ) + PROGRAM(), ; _Vfp.ServerName ), ; "log" ) ENDPROC PROCEDURE LogIt LPARAMETERS t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, ; t11, t12, t13, t14, t15, t16, t17, t18, t19, t20 *-------------------------------------------* Setup. *-------------------------------------------LOCAL lcCalledProgram, i, lcVar, laEvents[1], lcLogText *-------------------------------------------* Name der Klasse und der aufgerufenen * Methode. *-------------------------------------------IF AEVENTS( laEvents, 0 ) == 0 lcCalledProgram = PROGRAM(PROGRAM(-1)-1) lcCalledProgram = This.Name + "." + ; SUBSTR( lcCalledProgram, AT( ".", lcCalledProgram ) + 1 ) ELSE lcCalledProgram = This.Name + "." + ; laEvents[ 2 ] ENDIF *-------------------------------------------* Uhrzeit. *-------------------------------------------lcLogText = CHR(13) + ; "*** " + STRTRAN(TTOC(DATETIME(),3),"T", " ") + " ***" + ; CHR(13) + lcCalledProgram + CHR(13) *-------------------------------------------* Alle Parameter, die der aufgerufenen * Methode übergeben wurden, bzw. der Wert, * der von ihr zurückgegeben wurde. *-------------------------------------------FOR i = 1 TO PCOUNT() lcLogText = lcLogText + ; TRANSFORM(EVALUATE( "t" + LTRIM(STR( i )) )) + CHR(13) ENDFOR *-------------------------------------------* In Textdatei schreiben. *-------------------------------------------STRTOFILE( lcLogText, This.cLogFile, .T. ) *-------------------------------------------* Rückgabewert zurückgeben. *-------------------------------------------RETURN t1 ENDFUNC ENDDEFINE So sieht der Inhalt der Logdatei nach einem Aufruf der Methode GetData() aus. *** 2006-11-10 03:32:10 *** Protokoll.GETDATA 10 *** 2006-11-10 03:32:10 *** Protokoll.GETDATA Hallo Welt 13. Visual FoxPro Entwicklerkonferenz 2006 32 • D-WEB1 (Gruppe WEB) COM Server und WebServices in VFP und .NET © 2006 Markus Winhard Deployment Damit ein WebService auf einem Webserver installiert werden kann, müssen zuerst ein paar Vorausetzungen erfüllt sein. Neben dem obligatorischen Webserver IIS muß installiert sein: Die VFP Runtime. Das geht am leichtesten mit dem ProLib Runtime Installer (ftp://ftp.prolib.de/Public/VFP/ VFP9SP1RT.exe). SOAP 3.0. Hier gibt es die am einfachsten zu installierende Variante direkt von Microsoft: soapsdk.exe (http://www.microsoft.com/downloads/details.aspx?familyid=c943c0dd-ceec-4088-9753-86f052ec8450) Ein IIS-Skript-Mapping, das die Dateiendung WSDL dem SOAP3-Listener zuordnet. Das ist ein Zweizeiler in VFP: loWSHelper = NEWOBJECT( "_WebServices", ; IIF( VERSION(2)=0, "", HOME() + "FFC\" ) + "_WS3Utils.vcx" ) loWSHelper.CheckVDirMap( "IIS://localHost/w3svc/1/Root" ) Ob das Skript-Mapping bereits angelegt ist, können Sie auch hier nachsehen: Start > Einstellungen > Systemsteuerung > Verwaltung > Internetdienste-Manager > Standardwebseite > Eigenschaften > Basisverzeichnis > Konfiguration > Anwendungszuordnungen. Achtung: Das manuelle Eintragen dieser Zuordnung ist leider so wie es hier dargestellt ist nicht möglich, da der Standard-Installationspfad der SOAPIS30.dll ein Leerzeichen enthält. Faßt man den Installationspfad in Anführungszeichen, dann läßt sich die Zuordnung zwar speichern, aber sie funktioniert nicht. Wenn Sie die Zuordnung trotzdem einmal manuell vornehmen müssen, dann geben Sie den Pfad in MSDOS-8.3Schreibweise an. Die 8.3-Schreibweise einer Pfadangabe erhalten Sie am einfachsten, indem Sie eine MSDOSEingabeaufforderung öffnen, mit dem Befehl CD ins gewünschte Verzeichnis wechseln, und den Befehl “command” eingeben. COM Server und WebServices in VFP und .NET © 2006 Markus Winhard (Gruppe WEB) 13. Visual FoxPro Entwicklerkonferenz 2006 D-WEB1 • 33 Installation des COM Servers Da die Funktionalität von VFP WebServices in den zugehörigen COM Servern steckt, müssen wir die COM Server DLL auf dem WebServer registrieren. Als Beispiel verwende ich einen fiktiven “HalloWelt”-WebService. C:\Windows\System32\RegSvr32.exe HalloWelt.dll Das Installationsverzeichnis kann ein beliebiges Verzeichnis auf dem Webserver sein. Die von VFP beim Kompilieren ebenfalls generierten Dateien HalloWelt.TLB und HalloWelt.VBR müssen nach meiner Erfahrung nicht auf den WebServer kopiert werden. Installation der WSDL- und WSML-Dateien Zu einem WebService gehören eine WSDL-Datei und zwei WSML-Dateien. Kopieren Sie alle drei Dateien in ein Verzeichnis auf der Festplatte des Webservers, dem ein virtuelles Webverzeichnis zugeordnet ist. Grundsätzlich kann dafür auch das Verzeichnis C:\InetPub\wwwRoot\ verwendet werden, viele Administratoren sehen es aber nicht so gerne, wenn das Hauptverzeichnis ihres Webservers mit Dateien übersäht ist. Im Fall unseres fiktiven“HalloWelt”-WebService lauten die Dateinamen HalloWelt.WSDL HalloWelt.WSML HalloWeltClient.WSML Nach dem Kopieren der drei genannten Dateien muß die WSDL-Datei noch an Ihre neue Heimat angepaßt werden. Öffnen Sie dazu die Datei mit einem Text-Editor und suchen Sie am Ende der Datei den XML-Tag, der mit <soap:address location beginnt. Passen Sie den Domain-Namen und das virtuelle Verzeichnis an den neuen Installationsort an: <soap:address location='http://www.meinedomain.de/HalloWelt.WSDL'/> Ein erster Test in VFP Nach erfolgreicher Installation kann unser fiktiver “HalloWelt”-WebService von einem anderen PC aus getestet werden. Voraussetzung ist, daß auf diesem PC der SOAP Client 3.0 installiert ist. LOCAL loWS loWS = CREATEOBJECT( "MSSOAP.SoapClient30" ) loWS.MSSoapInit( "http://w2000/hallowelt.wsdl", ; "hallowelt", "halloweltSoapPort" ) ? loWS.HalloWelt() 13. Visual FoxPro Entwicklerkonferenz 2006 34 • D-WEB1 (Gruppe WEB) COM Server und WebServices in VFP und .NET © 2006 Markus Winhard Anlegen eines virtuellen Verzeichnisses im IIS Um die gezeigten Beispiele auf Ihrem PC auszuführen, erstellen Sie ein Verzeichnis devcon2006 auf Ihrer Festplatte. Erstellen Sie ein Unterverzeichnis D-WEB1 und entpacken Sie die Beispieldateien (D-WEB1_code.zip) in dieses Unterverzeichnis. Legen Sie anschließend ein virtuelles Verzeichnis /devcon2006 in ihrem lokalen Internet Information Server an und ordnen Sie diesem virtuellen Verzeichnis das soeben angelegte Verzeichnis devcon2006 auf Ihrer Festplatte zu. Dazu öffnen Sie die Windows Management Konsole Internet-Informationsdienste. Sobald der IIS installiert ist, finden Sie diese unter Start > Einstellungen > Systemsteuerung > Verwaltung > Internetdienste-Manager. COM Server und WebServices in VFP und .NET © 2006 Markus Winhard (Gruppe WEB) 13. Visual FoxPro Entwicklerkonferenz 2006 D-WEB1 • 35 13. Visual FoxPro Entwicklerkonferenz 2006 36 • D-WEB1 (Gruppe WEB) COM Server und WebServices in VFP und .NET © 2006 Markus Winhard COM Server und WebServices in VFP und .NET © 2006 Markus Winhard (Gruppe WEB) 13. Visual FoxPro Entwicklerkonferenz 2006 D-WEB1 • 37 Der Vollständigkeit halber: Ein WebService in .Net In Visual Studio 2005 legen Sie einen neuen WebService mit folgenden Schritten an: File > New Web Site > ASP.NET Web Service. Visual Studio 2005 legt eine neue Webseite für Sie an und gibt den folgenden Code vor. using using using using System; System.Web; System.Web.Services; System.Web.Services.Protocols; [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] public class Service : System.Web.Services.WebService { public Service () { //Uncomment the following line if using designed components //InitializeComponent(); } [WebMethod] public string HelloWorld() { return "Hello World"; } } Starten Sie den WebService mit Taste F5. 13. Visual FoxPro Entwicklerkonferenz 2006 38 • D-WEB1 (Gruppe WEB) COM Server und WebServices in VFP und .NET © 2006 Markus Winhard Die URL, die wir zum Aufruf dieses WebService aus VFP benötigen, finden durch einen Klick auf den Link Dienstbeschreibung. Der Aufruf aus VFP sieht dann so aus. LOCAL loService loService = CREATEOBJECT( "MSSOAP.SoapClient30" ) m.loService.MSSoapInit( ; "http://localhost:1055/WebService1/Service.asmx?WSDL", ; "Service", "ServiceSoap" ) ? m.loService.HelloWorld() Famous last words Dieses war der erste Streich… (so hieß es damals auch bei Wilhelm Busch) …und der zweite folgt sogleich. Nun ja, nicht gleich, aber morgen in meinem zweiten Vortrag. Sie sind jetzt bereits in der Lage, eigene COM Server und WebServices zu erstellen, zu debuggen und aus ASP.Net aufzurufen. Noch ein bischen Programmieren in Visual Studio 2005 gelernt und schon kanns losgehen mit der Erweiterung Ihrer VFP-Anwendungen ins Web. Aber halt! Ein paar wichtige Informationen brauchen sie noch. Besuchen Sie auch meinen zweiten Vortrag WebFrontends für VFP-Anwendungen und ich erzähle Ihnen den Rest. Bei Fragen zu diesem Skript oder den mitgelieferten Klassen erreichen Sie mich unter [email protected]. Ich stehe Ihnen auch gerne für Ihre Projekte zur Verfügung. COM Server und WebServices in VFP und .NET © 2006 Markus Winhard (Gruppe WEB) 13. Visual FoxPro Entwicklerkonferenz 2006 D-WEB1 • 39