Aufrufbare Interfaces im Überblick
Nach oben zu Web-Services verwenden - Index
Server, die Web-Services unterstützen, werden unter Verwendung von aufrufbaren Interfaces erstellt. In aufrufbare Interfaces werden Laufzeit-Typinformationen hineincompiliert (RTTI, RunTime Type Information). Auf dem Server werden die RTTI zur Interpretation der client-seitig erfolgten Methodenaufrufe herangezogen, so dass diese korrekt weiterverarbeitet werden können. Auf den Clients hingegen dienen die RTTI zum dynamischen Generieren einer Methodentabelle, über welche die Methoden des Interface aufgerufen werden.
Zur Erstellung eines aufrufbaren Interface müssen Sie ein Interfaces nur mit der Compiler-Option {$M+} compilieren. Die Nachkommen eines aufrufbaren Interface sind ebenfalls aufrufbar. Wenn ein aufrufbares Interface jedoch von einem anderen, nicht-aufrufbaren Interface abgeleitet ist, kann der Web-Service nur die Methoden verwenden, die in dem aufrufbaren Interface und dessen Ableitungen definiert sind. Die von den nicht-aufrufbaren Vorgängern geerbten Methoden werden ohne Typinformationen compiliert und können daher nicht als Bestandteil des Web-Services verwendet werden.
Bei der Definition eines Web-Service können Sie ein aufrufbares Interface von dem aufrufbaren Basis-Interface System.IInvokable ableiten. IInvokable ist in der Unit System definiert. IInvokable ist nahezu identisch mit dem Basis-Interface (IInterface), mit dem Unterschied, dass dieses Interface mit der Compiler-Option {$M+} compiliert wird. Mit der Compiler-Option {$M+} wird sichergestellt, dass das Interfaces sowie alle ihre Nachkommen RTTI beinhalten.
Der nachfolgende Quelltext definiert beispielsweise eine aufrufbares Interface, das zwei Methoden zur Codierung und Decodierung numerischer Werte enthält.
IEncodeDecode = interface(IInvokable) ['{C527B88F-3F8E-1134-80e0-01A04F57B270}'] function EncodeValue(Value: Integer): Double; stdcall; function DecodeValue(Value: Double): Integer; stdcall; end;
__interface INTERFACE_UUID("{C527B88F-3F8E-1134-80e0-01A04F57B270}") IEncodeDecode : public IInvokable { public: virtual double __stdcall EncodeValue(int Value) = 0 ; virtual int __stdcall DecodeValue(double Value) = 0 ; };
Hinweis: Ein aufrufbares Interface kann überladene Methoden verwenden – allerdings nur dann, wenn es möglich ist, die unterschiedlichen überladenen Methoden anhand der Parameteranzahl zu identifizieren. Je zwei überladene Versionen dürfen also nicht dieselbe Anzahl von Parametern (einschließlich der möglichen Parameteranzahl, die sich unter Berücksichtigung der Standardparameter ergibt) besitzen.
Bevor eine Web-Service-Anwendung dieses aufrufbare Interface verwenden kann, muss es bei der Aufruf-Registrierung registriert werden. Auf dem Server ermöglicht ein Aufruf-Registrierungseintrag der Invoker-Komponente (SOAPHTTPPasInv.THTTPSOAPPascalInvoker) die Identifizierung einer Implementierungsklasse, die für die Ausführung von Interface-Aufrufen verwendet wird. Auf Client-Anwendungen sorgt der Eintrag dafür, dass externe Interface-Objekte (SoapHTTPClient.THTTPRio) auf Informationen zugreifen können, durch die das aufrufbare Interface identifiziert wird und die angeben, wie das Interface aufgerufen werden kann.
Normalerweise erstellt der Web-Service-Client oder -Server den Code zur Definition von aufrufbaren Interfaces entweder durch das Importieren eines WSDL-Dokuments oder mithilfe des Web-Service-Experten. Wenn das WSDL-Importprogramm bzw. der Web-Service-Experte ein Interface generiert, wird die Definition standardmäßig in eine Unit eingefügt, die den gleichen Namen wie der Web-Service aufweist. Diese Unit umfasst sowohl die Interface-Definition als auch den Quelltext zur Registrierung des Interface bei der Aufruf-Registrierung ein. Die Aufruf-Registrierung ist ein Katalog aller registrierten aufrufbaren Interfaces, ihrer Implementierungsklassen und der Funktionen, die Instanzen der Implementierungsklassen erstellen. Der Zugriff darauf erfolgt über die globale Funktion InvRegistry, die in der Unit InvokeRegistry definiert ist.
Die Definition des aufrufbaren Interface wird dem interface-Abschnitt der Unit hinzugefügt, während der Quelltext zur Registrierung des Interface in den Initialisierungsabschnitt platziert wird. Der Registrierungsquelltext sieht folgendermaßen aus:
initialization InvRegistry.RegisterInterface(TypeInfo(IEncodeDecode)); end.
static void RegTypes() { InvRegistry()->RegisterInterface(__delphirtti(IEncodeDecode), "", ""); } #pragma startup RegTypes 32
Hinweis: Die uses-Klausel des Implementierungsabschnitts muss die Unit InvokeRegistry einschließen, damit der Aufruf an die Funktion InvRegistry definiert ist.
Die Interfaces von Web-Services müssen über einen Namespace verfügen, anhand dessen sie von allen anderen Interfaces sämtlicher möglicher Web-Services unterschieden werden können. Im obigen Beispiel ist kein Namespace enthalten. Wenn Sie nicht ausdrücklich einen Namespace hinzufügen, wird dieser automatisch von der Aufruf-Registrierung generiert. Der Namespace besteht aus einem String, der die Anwendung (die Variable AppNamespacePrefix), den Interface-Namen sowie den Namen der Unit, in der er definiert ist, eindeutig identifiziert. Wenn Sie keinen automatisch generierten Namespace verwenden möchten, können Sie den Namespace explizit mithilfe eines zweiten Parameters für den Aufruf RegisterInterface angeben.
Sie können zur Definition eines aufrufbaren Interface ein und dieselbe Unit-Datei gleichermaßen für Client- und Server-Anwendungen verwenden. Wenn Sie so vorgehen, sollten Sie die Unit, welche das aufrufbare Interface definiert, getrennt von der Unit verwalten, in die Sie die implementierenden Klassen schreiben. Da der generierte Namespace den Namen der Unit enthält, in welcher das Interface definiert ist, ermöglicht die gemeinsame Nutzung derselben Unit in sowohl Client- als auch Server-Anwendungen, dass diese automatisch denselben Namespace verwenden, sofern beide den gleichen Wert für die Variable AppNamespacePrefix verwenden.
Im obigen Beispiel werden in den Methoden dem Interface ausschließlich skalare Typen (Integer und Double) verwendet. Die Verwendung von nicht-skalaren Typen ist ebenfalls möglich, ist jedoch etwas arbeitsaufwendiger.