Remote Scripting

Veröffentlicht: 15. Jun 2000 | Aktualisiert: 08. Nov 2004
Von Jürgen Marsch

Das Internet zeichnet sich durch seine Arbeitsteilung aus: Der Arbeitsplatz-PC wird zum einfachen und meist auch recht dummen Client degradiert, und der Server wird zum Hintergrundarbeiter, der alles tut und alles weiß. Diese Konstruktion weist einige Nachteile gegenüber einer normalen Oberfläche auf. Mit Remote Scripting - ASP-Seiten können wie lokale Objekte angesprochen werden - wird hier ein möglicher Ausweg aus einigen Schwachstellen in der Arbeitsteilung von Client und Server gezeigt.

Auf dieser Seite

 Arbeitsweise von Remote Scripting
 Hello kommt vom Server
 So erzeugt der Server das Hello
 ASP-Funktionen als Methoden eines lokalen Objekts
 Asynchron geht´s auch - und Fehler werden abgefangen
 Die erste Anwendung: Das Autohaus AAK
 Jetzt holen wir (fast) ganze Objekte
 VBScript endlich überall
 Zusammenfassung

Diesen Artikel können Sie hier lesen dank freundlicher Unterstützung der Zeitschrift:

Bild03



Überblick
Thema
Wesentliche Funktionen im Internet befinden sich heute, und auch in Zukunft, auf Servern. Ihre Nutzung erfordert in Browsern für gewöhnlich sichtbare Roundtrips mit erneutem Seitenaufbau.
Bei Remote Scripting handelt es sich um eine von Microsoft vorgestellte Technologie, die es jedem Java- und JavaScript-fähigen Browser gestattet, ohne Anzeige einer neuen Seite Serverfunktionalität in ASP-Seiten zu nutzen.
Scriptfunktionen in ASP-Seiten können dabei auf dem Client wie Methoden lokaler Objekte eingesetzt werden.
Technik
Browser-Scripting, Active Server Pages
Voraussetzungen
IIS 4.0, ein JavaScript- und Java-fähiger Internet

Jeder, der von einem üblichen Desktop-Programm ins Internet wechselt, ist zunächst von der unkomplizierten Oberfläche begeistert. Und da es außerdem so schön einfach ist, über den Sourcecode einer Seite hinter ihre Kulissen zu schauen, lernt man auch schnell, diese Technik in eigenen Seiten anzuwenden.

Nach einiger Zeit kommen aber die ersten Bedenken: Die alte Oberfläche hatte ja auch ihre Vorteile. War die Arbeit doch meist flüssig und auch angenehm fürs Auge, wird die Anzeige im Internet hingegen bei jeder Kleinigkeit neu aufgebaut. Man fühlt sich an die Vergangenheit erinnert, als ein Terminal am Host noch die einzige Form der Datenverarbeitung darstellte.

Ein weiterer Schwachpunkt liegt in der Aktualität der Daten. Je nach Einstellung des Browsers werden nicht immer die aktuellen Daten vom Server geholt. Der IE bietet sogar eine Option, über die das automatische Abfragen neuer Seiten auf niemalsgesetzt werden kann. Und wer sich an einen so konfigurierten Browser setzt, der wundert sich, dass immer derselbe Inhalt auf dem Bildschirm erscheint. Besonders bei Datenbankabfragen kann das ganz böse Folgen haben.

Für den Programmierer ergeben sich noch zusätzliche Nachteile. So schön es auch sein mag, Ideen und Lösungen von anderen abzuschauen, so unschön ist es, wenn man sein eigenes Gedankengut öffentlich machen muss. Dazu kommt, dass im Internet die Verbindung zwischen Server und Browser nur für die Zeit einer Seitenanfrage besteht. Damit der Server weiß, was er mit dem Inhalt eines Formulars tun soll, das ihm der Browser geschickt hat, benötigt er weitere Informationen. Ein Änderungsformular z.B. beinhaltet deshalb neben den änderbaren Feldern oft noch versteckte Fragmente, die dem Server etwa verraten, welcher Datensatz in der Datenbank geändert werden soll. Sobald derartige Zusatzinformationen über mehrere Formulare und Frames hinweg verwaltet werden müssen, kann der Aufwand für eine Internetanwendung schnell ansteigen.

Einfacher ist es, wenn nicht bei jeder Änderung eine komplett neue Seite angefordert wird. Die Arbeit soll der Server zwar ruhig machen, jedoch besteht keine Notwendigkeit, dass der Anwender dies durch eine Neuanzeige ganzer Seiten bemerkt. Sourcecode und Know-how verblieben bei einer solchen Lösung ebenfalls auf dem Server.

Eine solche Funktionalität könnte man natürlich mit ActiveX-Komponenten, eigenen Java-Applets oder RDS realisieren. Der Praktiker kennt aber die damit verbundenen Probleme, z.B. bei der Kompatibilität der Browser u.a. in Bezug auf OCX-Controls. Also hat sich Microsoft aufgemacht und die universelle Remote Scripting-Technologie entwickelt.

Arbeitsweise von Remote Scripting

Remote Scripting soll einem beliebigen Internet Browser - nur JavaScript und Java müssen unterstützt werden - erlauben, ohne neue Seitenanforderung Daten an einen Server zu übertragen bzw. von ihm zu akzeptieren. Das vermeidet den üblichen Neuaufbau von Seiten und erlaubt die Nutzung von Scriptfunktionen in ASP-Seiten in der Weise, als seien sie Methoden eines Objekts auf dem Client.

Der Browser lädt dabei eine Seite vom Server, die z.B. ein Formular enthält. Statt den Formularinhalt jedoch nach Betätigung des Submit-Buttons an den Server zu schicken und als Antwort eine neue Seite zu erhalten, kann der Formularinhalt jetzt mittels Scriptcode auf dem Client ausgelesen und über Remote Scripting im Hintergrund an den Server gesendet werden. Die Seite in der Anzeige bleibt dabei unverändert! Die Antwort des Servers besteht dann auch nicht mehr in einer neuen HTML-Seite, sondern vielleicht nur aus einer Bestätigung, dass die Formulardaten korrekt verarbeitet wurden. Serverroundtrips finden mit Remote Scripting also weiterhin statt - sind für den Anwender jedoch nicht mehr sichtbar. Remote Scripting realisiert diese Funktionalität durch Einsatz einer JavaScript-Bibliothek sowie eines Java-Applets. Abbildung 1 zeigt den Informationsfluss beim Remote Scripting.

Bild01

Abbildung 1: Informationsfluss zwischen Internet Browser und Server mit Remote Scripting

Der Server liefert als erstes eine HTML-Seite, in der Remote Scripting genutzt werden soll. Darin ist über eine Include-Anweisung die JavaScript-Bibliothek rs.htm eingebunden, die gleichzeitig und transparent für den Entwickler das Remote Scripting Java-Applet mitzieht.

Über Scriptbefehle in rs.htm wird dieses Applet angesprochen und stellt die Verbindung zu den Scriptfunktionen einer ASP-Seite auf dem Server her. Auch in dieser Seite existiert eine Include-Anweisung, die den serverseitigen Teil von Remote Scripting integriert. Mit dessen Hilfe wird später die gewünschte Scriptfunktion aufgerufen. Der Serverteil schickt dann nach Abarbeitung der Funktion deren Ergebnis wieder an das Applet auf dem Client, damit das Resultat dort als Ergebnis eines lokalen Scriptaufrufs weiterverarbeitet werden kann.

Eine genauere Erläuterung der prinzipiellen Funktionsweise von Technologien wie Remote Scripting oder RDS findet sich in dieser Ausgabe im Artikel zum Thema XMLHttpRequest-Komponente. Dort wird ein ähnlicher, jedoch über Remote Scripting hinausgehender Mechanismus mit VB-Komponenten realisiert, der alle wesentlichen Merkmale von Remote Scripting erklärt.

Hello kommt vom Server

Bevor wir zum ersten Beispiel kommen, noch einmal eine Auflistung, was wir uns vom Einsatz des Remote Scripting erhoffen.

  • flüssigere Oberfläche ohne Neuaufbau der Anzeige

  • aktuelle Informationen unabhängig von Browser-Einstellungen

  • Kapselung unseres Know-hows auf dem Server

  • weniger Verwaltungsinformationen in Anwendungen

Wie bei jeder neuen Programmiersprache wollen wir auch hier mit dem altbekannten Hello World-Programm anfangen. Dazu wird ein einfaches HTML-Formular mit nur einem Button erzeugt. Beim Drücken dieses Buttons soll ein Text vom Server kommen und in einer Messagebox angezeigt werden. Der Aufbau des Formulars ist nicht sehr aufregend, der Aufruf eines Scripts auf dem Server hingegen ist etwas Neues, und deshalb wollen wir uns dafür etwas mehr Zeit nehmen.

... 
<BODY> 
<script language="JavaScript" src="/_ScriptLibrary/rs.htm"></script> 
<script language="JavaScript">RSEnableRemoteScripting("/_ScriptLibrary");</script> 
<Center>  
<h2>Erstes Beispiel für Remote Scripting</h2> 
<form> 
<input type=button name=bpFirst value="Hello-Sample" onclick="Hello()"> 
</Form> 
</Center> 
<SCRIPT LANGUAGE="javascript"> 
var serverURL = "first.asp"; 
function Hello() 
{ 
var co = RSExecute(serverURL,"Hello"); 
myCallBack(co); 
} 
function myCallBack(co) 
{ alert("CALLBACK\n\n" + ...... "return_value = " + co.return_value); 
}  
</SCRIPT> 
...

An dieser Stelle ein kurzer Hinweis für alle VBScript-Freunde: Auch im weiteren Verlauf des Artikels wird relativ viel JavaScript erscheinen. Zielrichtung im Internet ist es ja, eine möglichst breite Besuchermenge zu erreichen - da nicht davon ausgegangen werden kann, dass überall der IE eingesetzt wird (nur er unterstützt VBScript), bietet sich das allgemeingültigere JavaScript für unsere Aufgabe an. Außerdem gibt es in JavaScript einige Befehle, die es in VBScript noch nicht gibt. Aus diesen Gründen ist Remote Scripting in dieser Sprache geschrieben worden. Die häufige Benutzung von JavaScript soll jedoch nicht den Eindruck erwecken, dass sich Remote Scripting nur damit betreiben ließe. Auch der Einsatz von VBScript auf Server und Client ist möglich (und wir werden darauf eingehen).

Nun aber hinein ins obige Listing für die Client-Seite: Direkt in den ersten Zeilen steht ein entscheidender Passus: Dort wird eine Verbindung zur Remote Scripting JavaScript-Library geschaffen, in der Microsoft einige Routinen für Remote Scripting zusammengefasst hat. Im Beispiel sind diese Routinen im Standard-Ordner namens _ScriptLibrary abgelegt. Die Verweise auf diesen Ordner werden relativ zum aktuellen Pfad angegeben.

Achtung an dieser Stelle: Remote Scripting achtet aus Gründen der Sicherheit erfreulicherweise darauf, dass für den Methodenaufruf kein anderer Rechner als der Lieferant der HTML-Seite angesprochen werden kann!

Im zweiten Script-Teil wird die erste Methode aus der Remote Scripting-Library, RSEnableRemoteScripting, aufgerufen. Ein Blick in den Bibliothekscode ist für den Spezialisten an dieser Stelle Pflicht: Über diese Funktion wird ein Applet in der aktuellen Seite plaziert. Microsoft ist sehr stolz auf die Tatsache, dass man im Sourcetext der Seite keinen Hinweis auf dieses Applet finden kann und erwähnt dies explizit in der Dokumentation. Außerdem wird in der Routine ein MSRS-Objekt angelegt, das im Verlauf der Bearbeitung benötigt wird, für den Programmierer aber verborgen bleibt.

Der Inhalt des Formulars besteht aus Standard-HTML, deshalb springen wir weiter zum interessanten Teil, der ebenfalls in JavaScript gehalten ist. Als erstes finden wir dort einen Verweis auf die ASP-Datei, in der die Methoden stehen, die wir vom Client her aufrufen wollen.

Darauf folgt der Aufruf der Server-Funktion Hello. Sie liefert statt eines normalen Funktionsresultats ein CallBack-Objekt zurück. In diesem findet man außer den eigentlichen Nutzdaten noch einige Steuerinformationen (siehe Tabelle 1). Auch hier wird der interessierte Leser in der Datei rs.htm die entsprechende Realisierung in JavaScript finden. Wer sich näher damit beschäftigt, wird erkennen, dass im Data-Feld bereits Ansätze von XML zu finden sind.

Die letzte Methode ist nicht besonders aufregend: Sie beschäftigt sich mit dem Ergebnis und zeigt es in Form einer Messagebox an (siehe Abbildung 2). Beachtenswert ist lediglich, welchen Aufbau das dafür benutzte CallBack-Objekt aufweist (Tabelle 1).

Eigenschaft

Erläuterung

Status

Rückgabestatus kann sein: MSRS_COMPLETED,
MSRS_FAIL, MSRS_PENDING, MSRS_PARTIAL

Message

Mitteilung des Servers zur Rückmeldung

Data

Rückgabewert in XML-Syntax

return_value

Aufbereiteter Rückgabewert

Callback

Client-Methode bei asynchroner Ausführung

error_callback

Methode, die im Fehlerfall aufgerufen wird

Context

Kontext der Ausführungsumgebung

Tabelle 1: Aufbau des CallBack-Objekts

Systemdateien (Library)

Microsoft hat die Installation für Remote Scripting sehr einfach gehalten: Die entsprechenden Dateien müssen nur an der richtigen Stelle stehen. Für die Remote Scripting-Bestandteile ist es das Verzeichnis _ScriptLibrary im Basisverzeichnis des Webservers, üblicherweise also unter \inetpub\wwwroot. Für das Remote Scripting-Verzeichnis wird das Scriptingrecht benötigt.

Programme

Eigene Programme, d.h. ASP-Seiten, können an einer beliebigen Stelle untergebracht werden. Es ist nur darauf zu achten, dass die Verweise auf die Library-Dateien stimmen. In den Beispielen auf der Heft-CD ist ein Ordner RemoteScriptingBP enthalten, der einfach in das Basisverzeichnis des Servers kopiert wird. Beim Autor hat es sich als sinnvoll erwiesen, diesen Ordner zusätzlich als virtuelles Verzeichnis (bprs) mit Scriptingrechten einzurichten.

Datenbank

Bei der Installation des RemoteScriptingBP-Verzeichnisses ist die Datenbank für das AAK-Beispiel bereits in das Unterverzeichnis Autohaus mitkopiert worden. Es wird jedoch noch ein ODBC-System-DSN mit Namen bprs für die Datei bprs.mdb benötigt.

Server

Zum Betrieb wird Microsoft IIS 4.0 benötigt. Mit älteren Versionen scheiterten die Versuche des Autors.

Client

Auch beim Client wird mindestens eine 4er-Version benötigt. Dabei ist es egal, ob es sich um den Netscape Navigator oder den Internet Explorer handelt. Wichtig ist, dass bei Browser auch die Akzeptanz für JavaScript und Java aktiviert sind.

Kasten 1: Installation von Remote Scripting

So erzeugt der Server das Hello

Nachdem die Client-Seite, zumindest in dieser einfachen Form, erklärt ist, wenden wir uns dem Server zu. Bisher haben wir auf dem Client nur die URL einer ASP-Seite mit Scriptfunktionen benutzt. Aber auch dort muss noch irgend etwas stehen, das die Kommunikation zwischen Client und Server per Remote Scripting ermöglicht. Das folgende Listing zeigt die Hello World-ASP-Seite:

<%@ LANGUAGE=VBSCRIPT %> 
<% RSDispatch %> 
<SCRIPT RUNAT=SERVER Language=javascript> 
<!--#INCLUDE FILE="../../_ScriptLibrary/rs.asp"--> 
function Description() 
{this.Hello = Hello; 
} 
public_description = new Description(); 
function Hello() 
{return "Hello, bp ist doch immer und überall"; 
} 
</SCRIPT>

Auch dort gibt es, wie im Client-Teil, eine zusätzliche Bibliotheksdatei, mit der Microsoft uns die Arbeit erleichtert hat. Wichtig soll hier für uns nur sein, dass die Adressierung der Datei wie im Muster, also relativ zum Verzeichnis der aufgerufenen ASP-Seite, erfolgen sollte.

Interessanter wird es danach: Nach guter alter JavaScript-Manier wird ein Objektkonstruktor namens Description aufgebaut, dessen einziger Zweck darin besteht, eine Verbindung zu der eigentlichen Methode zu schaffen (vgl. dazu die Erläuterung zur HttpRPC-Komponente im XMLHttpRequest-Artikel dieses Hefts). Die Hello-Methode ist dann auch sehr einfach aufgebaut und gibt nur einen Ergebnisstring zurück. Ein Punkt, den man sich unmittelbar merken kann: Funktionsresultate sind immer Strings! Das gilt auch für Parameter, die vom Client in ASP-Funktionen hineingereicht werden. Wie - und dass - man aber trotz dieser Beschränkung mit Remote Scripting viel anfangen kann, wird im weiteren Verlauf noch dargelegt.

Nach Installation von Remote Scripting (Kasten 1) und Aufruf von first.htm (siehe Beispiele auf der Heft-CD) sollte sich nach Betätigung des Hello-Sample-Buttons ein zu Abbildung 2 vergleichbares Ergebnis ergeben.

Bild02

Abbildung 2: Hello mit Remote Scripting

Es geht auch mit Parametern und in VB

Als VB-Freunde wollen wir uns nun, wenn auch nur kurz, mit dem beschäftigen, was wir am besten können - wenn es möglich ist, JavaScript in Remote Scripting zu nutzen, sollte es mit VBScript auch keine größeren Probleme geben. Um es nicht zu kompliziert zu machen - es geht ja um das Prinzip und nicht um die Inhalte - addieren wir einfach zwei Zahlen:

<SCRIPT RUNAT=SERVER LANGUAGE="VBScript"> 
Function addNumbers(num1, num2) 
addNumbers = CInt(num1) + CInt(num2) 
End Function 
</SCRIPT>

Da alle Parameter als String bei der ASP-Seite angeliefert werden, ist vor der Berechnung eine Umwandlung in Zahlen notwendig. Man sollte bei Scripts, die rechnen, nicht auf eine Konvertierung verzichten. Ansonsten kann es zu der versehentlichen Mischung von Zahlen und Strings und damit zu unerwarteten Ergebnissen kommen.

Weiter oben wurde gezeigt, dass die Methoden in das Description-Objekt eingebunden werden müssen, bevor sie genutzt werden können. Bei exklusiven JavaScript-Scripten war das recht einfach.

this.Hello = Hello;

Bei einem Sprung über Sprachgrenzen hinweg wird jedoch etwas mehr Aufwand erforderlich:

this.add = Function( 'n1','n2','return addNumbers(n1,n2)' );

Die VBScript-Funktion ist in JavaScript nicht als Objekt bekannt. Also müssen wir dynamisch ein JavaScript-Funktionsobjekt erzeugen. Über den Funktionsnamen add kann die Funktion später vom Client aus angesprochen werden. Parameter und Funktionsrumpf sind an den Konstruktor des Funktionsobjekts als Argumente zu übergeben. Das letzte Argument ist immer der Funktionsrumpf, der hier nur aus dem Aufruf der VBScript-Routine besteht (der Name der JavaScript-Funktion, add, und der VBScript-Funktion, addNumbers, müssen nicht identisch sein (können es aber); beim Client ist immer nur der Methodenname des public_description-Objekts sichtbar). Alle angeführten Argumente stellen Parameter für diesen Aufruf dar.

Vorsicht: JavaScript ist bezüglich Groß-/Kleinschreibung sehr sensibel. Es sollte also immer darauf geachtet werden, dass alle Namen exakt so geschrieben werden, wie sie definiert sind.

Beim Aufruf auf der Client-Seite werden JavaScript- und VBScript-Routinen identisch behandelt:

function handleRSExecuteVB() 
{ 
var co = RSExecute(serverURL,"add","-7","9"); 
myCallBack(co); 
}

Interessant ist hier, dass die Parameter nicht im String zusammen mit dem Methodennamen übergeben werden, sondern als eigene Parameter folgen. Dank dieser Arbeitsweise wird die Umsetzung auf dem Server vereinfacht.

Im Listing wurde der einfachste Weg beschritten, auf dem man Parameter übergeben kann. Natürlich kann man sich bei einem Formular auch alle Informationen aus einem Textfeld holen, wie es im Beispiel auf der Heft-CD vorgeführt wird.

ASP-Funktionen als Methoden eines lokalen Objekts

Bisher haben wir Serverfunktionen immer relativ unhandlich über RSExecute aufgerufen. Das ist etwas unintuitiv, wenn man gewohnt ist, in Objekten und Methoden zu denken. Remote Scripting bietet aber noch einen weiteren Weg, auf die ASP-Funktionen zuzugreifen:

var aspseite = RSGetASPObject(serverURL); 
var co = aspseite.add("-7", "9");

Indem einmalig pro ASP-Seite ein Verbindungsobjekt (z.B. aspseite) erzeugt wird, stehen die ASP-Funktionen anschließend als Methoden dieses Objekts bereit. Lediglich das CallBack-Objekt gibt noch einen Hinweis darauf, dass es sich bei add nicht wirklich um eine lokale Methode handelt.

Asynchron geht´s auch - und Fehler werden abgefangen

Bisher haben wir uns damit abgefunden, dass wir auf das Ergebnis des Klicks warten müssen. Im Arbeitsablauf kann es aber sinnvoll sein, den Anwender schon einmal etwas weiterarbeiten zu lassen, auch wenn der Server noch nicht fertig ist. Normale Programme erlauben es ja auch häufig, dass während einer zeitaufwendigen Aktion schon die nächsten Bedienungen möglich sind. Bei etwas langsameren Rechnern kann man z.B. bei Word einen gewissen Nachlauf der eingegebenen Zeichen (verursacht durch die Rechtschreibprüfung) beobachten.

Im Internet kommen noch ganz andere Zeitfaktoren ins Spiel, außerdem ist das gesamte Medium nicht auf synchrones Arbeiten angelegt. Deshalb gibt es auch bei Remote Scripting die Möglichkeit, asynchrone Aktionen durchzuführen. Dazu wird lediglich ein weiterer Parameter eingeführt, der angibt, welche Methode auf dem Client aufgerufen werden soll, sobald das Ergebnis zur Verfügung steht. Aus dem bisher bekannten Aufruf wird dadurch die folgende Routine:

function handleRSExecuteAsync() 
{RSExecute(serverURL,"Method1",myCallBack,"RSExecute"); 
}

Die bisherigen zwei Zeilen werden nun zu einer. Dabei werden nur zwei Parameter an den schon bekannten Aufruf angehängt, wobei der erste Parameter die Methode angibt, die bei bereitstehendem Ergebnis aufgerufen werden soll. Der Einfachheit halber nehmen wir das schon vorhandene myCallBack. Der zweite neue Parameter soll das Umfeld angeben, in dem RSExecute mit den ersten Parametern ausgeführt werden soll. In verteilten Anwendungen über den ganzen Globus hinweg kann es durchaus interessant werden, zusätzliche Informationen zu überbringen.

Um auch auf Fehler während der asynchronen Verarbeitung reagieren zu können, ist es möglich, über einen weiteren Parameter eine Fehlerbehandlungsroutine zu spezifizieren, die mit einem On Error Gosub-Handler vergleichbar ist:

function handleInvalidCall() 
{var co = RSExecute(serverURL,"Method3",myCallBack,errorCallBack,"Invalid 
RSExecute");  
}

In der Fehlerroutine selbst wird wieder das Callback-Objekt ausgewertet. Nur den return_Value können wir uns sparen. Im Fehlerfall ist dieser Wert verständlicherweise ohne jeden Wert, zumindest für den Anwender.

function errorCallBack(co) 
{alert("ERROR_CALLBACK\n\n" + 
"status = " + co.status + "\n\n" + 
"message = " + co.message + "\n\n" + 
"context = " + co.context + "\n\n" + 
"data = " + co.data); 
}

Die erste Anwendung: Das Autohaus AAK

Nachdem in den bisherigen Abschnitten die Grundlagen von Remote Scripting behandelt wurden, wollen wir jetzt mit einer Mini-Anwendung beginnen. Datenbanken sind auch im Internet nicht mehr wegzudenken - als Fallbeispiel hierfür soll ein Autohaus dienen. Unser Autohaus AAK (Arnes Alte Kutschen) hat eine Datenbank angelegt, in der die Kunden in Verbindung mit ihren Autos gespeichert sind. Alle Einträge können in einer Liste betrachtet werden, und wenn man weitere Informationen zum Kunden braucht, werden diese einfach eingeblendet. Und was beim Kunden wichtig ist, gilt in diesem Fall natürlich auch für das Auto.

Eine derartige Anwendung kann natürlich auch mit HTML, ASP und Frames aufgebaut werden - dann aber würden uns die Vorteile des Remote Scripting verwehrt bleiben.

Zunächst ein paar kurze Bemerkungen zum Aufbau der Datenbank: Im Zentrum steht eine Datei mit den Angaben, welcher Kunde welche Autos hat. Über Schlüsselfelder kommt man dann zu Angaben über die Automarke oder zum Kunden. Im Beziehungsfenster der Access-Datenbank kann man diesen Zusammenhang sehr gut erkennen.

So ein Autohaus hat natürlich auch Mitarbeiter, und zum Einstieg werden wir uns genau mit diesen beschäftigen. Die Technik zur Erstellung einer ASP-Anwendung mit Datenbankzugriff soll hierbei allerdings nicht tiefgreifend betrachtet werden.

In der Datei global.asa wird eine Verbindung zur Datenbank aufgebaut und zur weiteren Nutzung in einer Session-Variablen gespeichert. Die Datenbank wurde vorher als System-DSN unter ODBC in der Systemsteuerung angelegt (siehe auch Kasten 1).

Die DBSimple-Dateien zeigen die prinzipiellen Schritte, die unternommen werden. Nachdem die Verbindung zur Datenbank ja schon besteht, wird mit dem ersten Button ein Recordset geöffnet und, wie die Verbindung zur Datenbank, in einer Session-Variablen gespeichert (die Speicherung von Connection- und Recordset-Objekten in Session-Variablen ist einfach und für unsere Zwecke ausreichend, für größere Anwendungen jedoch nicht zu empfehlen, da damit die Ausführung der ASP-Seite an einen Thread gebunden wird). Mit dem zweiten Button wird das erste Feld des Recordsets zurückgegeben. Vorgehensweise und Technik sind so einfach, dass wir uns mit Listing 1 zufrieden geben wollen.

<SCRIPT RUNAT=SERVER Language=javascript> 
<!--#INCLUDE FILE="../../_ScriptLibrary/rs.asp"--> 
function Description() 
{this.JavaFields = JavaFields; 
 this.InitRS = Function('Sql','return InitRS(Sql)'); 
 this.RSField = Function('fld','return RSField(fld)'); 
} 
public_description = new Description(); 
function JavaFields() 
{return new Array(RSField(0),RSField(1),RsField(2)); } 
</SCRIPT> 
<SCRIPT RUNAT=SERVER LANGUAGE="VBScript"> 
Function InitRS(sql) 
Dim Db, Remote Scripting 
Set Db = Session("DB") 
Set Remote Scripting = Db.Execute(sql) 
Set Session("Remote Scripting") = Remote Scripting 
InitRs = true  
End Function 
Function RSField(fld) 
Set Remote Scripting = Session("Remote Scripting") 
RSField = Remote Scripting.Fields(fld) 
End Function 
</SCRIPT>

Listing 1: Einfache Zugriffe auf die AAK-Datenbank

Nur eine Stelle bedarf einer weiteren Erläuterung. Das Lesen eines Feldes aus der Datenbank ist nicht sonderlich schwierig - sobald aber mehrere Felder gelesen werden müssen, und das ist bei einer Datenbank-Abfrage fern von ungewöhnlich, steigen Netz- und Server-Belastung stark an, da für jedes Feld der gleiche Overhead notwendig wird. Sinnvoller wäre es, wenn alle Felder des Recordsets übergeben werden könnten. Wer sich anhand des Sourcecodes des Second-Beispiels schlaugemacht hat, findet dort eine Stelle, in der ein ganzes Array aus JavaScript heraus übergeben wird. In Listing 1 wird die gleiche Technik genutzt, um mehrere Felder eines Recordsets in einer Antwort zurückzugeben.

return new Array(RSField(0),RSField(1),RsField(2));

Leider entsteht dadurch auf der Client-Seite erhöhter Aufwand. Im CallBack-Objekt (siehe Tabelle 1) gibt es für die Rückgabe nur Data und ReturnValue. Ein Blick auf das Ergebnis des dritten Buttons zeigt unser Dilemma: Im ReturnValue sind alle Felder enthalten - jedoch alle zusammen in einem String, lediglich durch Kommata getrennt. Ein zusätzliches Komma in einem Feldwert wirkt da gleichermaßen letal auf die weitere Auswertung.

Im Data-Feld hingegen kann man bei genauerem Hinschauen eine sauberere Trennung erkennen, einfacher scheint die Ermittlung der einzelnen Felder aber nicht unbedingt. Doch auch hier hilft ein Blick in den Sourcecode der Datei rs.htm. Dort findet man in der Methode _MSRS_evaluateRequest folgende Programmzeile:

request.return_value = eval(unescape(request.return_value));

Mithilfe einer Messagebox kann man jetzt das unescape auf das Data-Feld anwenden und erhält dabei eine Zeile mit folgendem Inhalt:

var undefined; 
var _o0= new Array(3);_o0(0)=Klawuttke;_o0(1)=Erwin,;_o0(2)=12345; 

Da diese Zeile mit dem eval-Befehl in JavaScript bearbeitet wird, um den return_value zu erzeugen, können wir den Inhalt des Arrays natürlich auch entsprechend abfragen, um z.B. den Namen zu ermitteln. Der eval-Befehl ist ein Beispiel dafür, was in VB schon immer gefehlt hat - in VBScript ab Version 5.0 aber jetzt endlich auch enthalten ist. Was könnte man damit nicht alles anstellen ...

alert("Field:" + co.return_value[0]);

Das Programmbeipiel geht einen Schritt weiter und nutzt für das Feld keinen festen Wert, sondern ein Select-Feld aus dem Formular, um über die Oberfläche den gewünschten Wert anwählen zu können.

Anhand der Beispiele kann man sich an die Analyse des Programmaufbaus für das Autohaus AAK begeben - der vollständige Code dafür ist online enthalten.

Jetzt holen wir (fast) ganze Objekte

Nachdem wir im letzten Abschnitt gesehen haben, wie man Arrays als Parameter übergeben kann, wollen wir uns noch etwas tiefer mit der Schnittstelle zwischen Client und Server beschäftigen. Die entsprechenden Beispiele findet man im zugehörigen Quellcode im Ordner RSTester.

Zunächst interessiert uns, was auf dem Server ankommt, wenn eine Methode aufgerufen wird. Auf dem Server bekommt man diese Information im Request-Objekt geliefert, so dass die Abfrage mittels ASP recht einfach ist. Auf der Client-Seite wird die inzwischen vertraute Messagebox zur Anzeige benutzt.

Zur Erläuterung des Ergebnisses übergehen wir die einfache Version (in der Testseite ist natürlich auch dieser Teil enthalten) und zeigen direkt die Version mit Parameterübergabe. Der Sourcecode für Server und Client ergibt sich wie folgt:

// Client-Teil: 
function handleRequesterWithParam() 
{var co = RSExecute(serverURL,"RequesterWithParam",12,"Hugo"); 
myCallBack(co); 
} 
// Serverteil: 
Function VBRequest() 
VBRequest = Request.QueryString 
End Function

Das Ergebnis ist im return_value des CallBack-Objekts zu finden. Für jeden Aufruf werden mindestens drei Parameter übergeben. Der erste Teil (_method) beinhaltet den Namen der aufzurufenden Methode. Im nächsten Teil (_mtype) folgt der Typ, mit dem der Aufruf auf dem Server erfolgen soll. Der dritte Teil schließlich beinhaltet die Parameter. Über pcount wird dem Server mitgeteilt, wie viele Parameter folgen. Danach folgen dieser Angabe entsprechend die einzelnen Parameter. Die Namengebung ist recht einfach: auf p0 folgt p1 usw. Hier das Ergebnis des obigen Beispiels:
_method=RequesterWithParam&_mtype=execute&pcount=2&p0=12&p1=Hugo
Nach diesem einfachen Beispiel steigt die Neugier, wie Parameter zurückgegeben werden. In den bisherigen Abschnitten war dazu schon Einiges zu lesen. Deshalb wollen wir jetzt einen Schritt weiter gehen. Wenn es so einfach war, ein Array zu übergeben, wie sieht dann ein Objekt aus? Achtung: Es handelt sich dabei nicht um COM-Objekte, sondern JavaScript-Objekte!

Auf der Serverseite machen wir es uns recht einfach und erzeugen ein simples Objekt mit JavaScript, das wir als Parameter zurückgeben:

function newobject() 
{this.firstfield = "First"; 
this.secondfield = "Second"; 
} 
function GetNewObject() 
{return new newobject(); 
}

Einfacher geht es wohl kaum. Wie dieses Objekt ankommt, zeigt uns die nunmehr heißgeliebte Messagebox. Leider ist dabei nicht viel zu erkennen: Es wird lediglich [object Object] angegeben. Nehmen wir also wieder das Data-Feld aus dem CallBack-Objekt auseinander - wir sehen, dass alles vorhanden ist, was auf dem Server auch erstellt wurde. Es drängt sich der Verdacht auf, dass der Zugriff mit den üblichen Befehlen gelingen sollte. Mit folgendem Beispiel klappt dies dann auch hervorragend:

alert("firstfield:" + co.return_value.firstfield);

Mit dem entsprechenden Button auf der Testseite kann man dies natürlich sofort ausprobieren. Das darauffolgende Beispiel geht dann einen Schritt weiter: Dort wird ein Objekt mit mehreren Unterobjekten zurückgegeben. Die Syntax des Zugriffs und die Umsetzung ähneln dem letzten Beispiel, deshalb sparen wir uns eine weitere Prüfung. Wenden wir uns lieber dem nächsten Versuch zu.

Ein Objekt besteht meist nicht nur aus Parametern, sondern auch aus Methoden. Nur zum Test versuchen wir deshalb einmal, ein Objekt mit Methoden zu übergeben. Die Erstellung erfolgt wieder in JavaScript:

function realobject() 
{this.firstfield = "First"; 
this.concat = realobject_concat; 
} 
function realobject_concat() 
{return "this is unbelievable"; 
} 
function GetRealObject() 
{return new realobject(); 
}

Unser letzter Button im RSTest-Beispiel zeigt dem interessierten Leser, welches Ergebnis an den Client übergeben wird. Erstaunlicherweise sieht man im Data-Feld, dass die Methodendefinition tatsächlich über das Internet vom Server an den Client geschickt wird. Und damit nicht genug: Die Definition wird auch eingebunden und ist somit mit folgenden Befehlen auch auf dem Client nutzbar:

function handleRealObject() 
{var co = RSExecute(serverURL,"GetRealObject"); 
myCallBack(co); 
alert("Concat-Methode(Inhalt):" + co.return_value.concat); 
alert("Concat(Ergebnis):" + co.return_value.concat()); 
}

VBScript endlich überall

Erneut sind wir bei dem Punkt angelangt, an dem ein Blick in Richtung VBScript sinnvoll erscheint. Beschäftigen wir uns dazu erst mit dem Client - unserem Browser. Wer für einen übersichtlichen Bereich arbeitet, in dem durch eine EDV-Abteilung die Verwendung des IE sichergestellt werden kann, kann sich eine intensive Einarbeitung in JavaScript sparen. Alles, was wir bisher auf dem Client gemacht haben, geht dann auch in VBScript. Nur bei der Syntax gibt es einen kleinen Unterschied: Während bei JavaScript ein Objekt genauso behandelt wird wie eine einfache Variable, sieht das in VBScript anders aus. Dort wird ein zusätzliches Set benötigt.

function handleRequesterVB() 
dim co 
set co = RSExecute("RSTestVB.asp","Requester") 
msgbox "Request(VB):" + co.return_Value 
end function

Auch die im letzten Abschnitt besprochenen Spezialitäten sind möglich. Sogar die Ausführung einer vom Server gelieferten Methode, siehe concat, wird klaglos umgesetzt.

Auf dem Server ist VBScript ja schon eine bekannte Angelegenheit: Jede ASP-Seite kann diese Sprache nutzen. Da mit Remote Scripting leider kein Recordset als Objekt an den Client zurückgeliefert werden kann, hier nun ein Beispiel, wie man mithilfe einer einfachen Umgehungsprozedur trotzdem an die benötigten Informationen kommt:

function GetRS() 
{cnt = OpenRS(); 
a = new Array(cnt + 1); 
a[0] = cnt; 
for (i = 1; i <= cnt; i++) 
{a[i] = GetRSField(i - 1);} 
CloseRS(); 
return a; 
}

Anstelle eines Recordsets wird ein Array benutzt. Dort sind die Felder wiederzufinden, die ansonsten in der Fields-Collection stehen. Zum Auffüllen des Arrays kann wieder VBScript genutzt werden:

Function OpenRS() 
Set db = Session("DB") 
Set rs = db.execute("Select * from ABF_Autos order by name,Hersteller") 
Set Session("Remote Scripting") = rs 
OpenRS = rs.fields.count 
End Function 
Function GetRSField(i) 
GetRSField = Session("Remote Scripting").fields(i) 
End Function

Zusammenfassung

Zuerst eine Wiederholung für den aufmerksamen Leser. Ein wichtiger Punkt, besonders für VB-Programmierer, betrifft die Groß-/Kleinschreibung - alles, was mit Java anfängt, ist in dieser Beziehung äußerst empfindlich.

Im Artikel war sehr viel von JavaScript die Rede. Im Internet hat das durchaus vergleichbare VBScript, zumindest auf der clientseitigen Ebene, bei weitem nicht diese Verbreitung gefunden und ist somit als clientseitige Scriptsprache nur äußerst bedingt verwendbar. Durch das Scheitern anderweitiger Unterstützung ist auch für den VB-Profi ein Seitenblick auf JavaScript notwendig geworden. Diejenigen, die das nicht abgeschreckt hat, wurden durch die Aussicht in eine andere Welt belohnt, die auch ihre eigenen schönen Seiten hat.

Im Remote Scripting sind Möglichkeiten enthalten, die im Netz für ganz neue Vorgehensweisen stehen können. Die Oberfläche wird handlicher und die Programmierung kann Wege gehen, die bisher unüblich waren - man denke nur an die Übergabe von Methoden über das Netz. Nachdem die Versuche von Microsoft, die eigene Technik mithilfe von ActiveX-Komponenten und -Dokumenten auf breiter Basis zu etablieren, nicht ansatzweise als erfolgreich zu bezeichnen sind, hat man sich wohl auf etwas anderes besonnen. Dass dabei keine neue Abhängigkeit entstand (denn Java und JavaScript laufen auf allen gebräuchlichen Browsern), kann für Anwender und Programmierer nur von Vorteil sein.


Anzeigen: