Understanding Invokable Interfaces
Go Up to Using Web Services Index
Servers that support Web Services are built using invokable interfaces. Invokable interfaces are interfaces that are compiled to include runtime type information (RTTI). On the server, this RTTI is used when interpreting incoming method calls from clients so that they can be correctly marshaled. On clients, this RTTI is used to dynamically generate a method table for making calls to the methods of the interface.
To create an invokable interface, you need only compile an interface with the {$M+} compiler option. The descendant of any invokable interface is also invokable. However, if an invokable interface descends from another interface that is not invokable, your Web Service can only use the methods defined in the invokable interface and its descendants. Methods inherited from the non-invokable ancestors are not compiled with type information and so can't be used as part of the Web Service.
When defining a Web service, you can derive an invokable interface from the base invokable interface, System.IInvokable. IInvokable is defined in the System unit. IInvokable is the same as the base interface (IInterface), except that it is compiled using the {$M+} compiler option. The {$M+} compiler option ensures that the interface and all its descendants include RTTI.
For example, the following code defines an invokable interface that contains two methods for encoding and decoding numeric values:
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 ; };
Note: An invokable interface can use overloaded methods, but only if the different overloads can be distinguished by parameter count. That is, one overload must not have the same number of parameters as another, including the possible number of parameters when default parameters are taken into account.
Before a Web Service application can use this invokable interface, it must be registered with the invocation registry. On the server, the invocation registry entry allows the invoker component (Soap.SOAPHTTPPasInv.THTTPSoapPascalInvoker) to identify an implementation class to use for executing interface calls. On client applications, an invocation registry entry allows remote interfaced objects (Soap.SOAPHTTPClient.THTTPRIO) to look up information that identifies the invokable interface and supplies information on how to call it.
Typically, your Web Service client or server creates the code to define invokable interfaces either by importing a WSDL document or using the Web Service wizard. By default, when the WSDL importer or Web Service wizard generates an interface, the definition is added to a unit with the same name as the Web Service. This unit includes both the interface definition and code to register the interface with the invocation registry. The invocation registry is a catalog of all registered invokable interfaces, their implementation classes, and any functions that create instances of the implementation classes. It is accessed using the global InvRegistry function, which is defined in the InvokeRegistry unit.
The definition of the invokable interface is added to the interface section of the unit, and the code to register the interface goes in the initialization section. The registration code looks like the following:
initialization InvRegistry.RegisterInterface(TypeInfo(IEncodeDecode)); end.
static void RegTypes() { InvRegistry()->RegisterInterface(__delphirtti(IEncodeDecode), "", ""); } #pragma startup RegTypes 32
Note: The implementation section's uses clause must include the InvokeRegistry unit so that the call to the InvRegistry function is defined.
The interfaces of Web Services must have a namespace to identify them among all the interfaces in all possible Web Services. The previous example does not supply a namespace for the interface. When you do not explicitly supply a namespace, the invocation registry automatically generates one for you. This namespace is built from a string that uniquely identifies the application (the AppNamespacePrefix variable), the interface name, and the name of the unit in which it is defined. If you do not want to use the automatically-generated namespace, you can specify one explicitly using a second parameter to the RegisterInterface call.
You can use the same unit file to define an invokable interface for both client and server applications. If you are doing this, it is a good idea to keep the unit that defines your invokable interfaces separate from the unit in which you write the classes that implement them. Because the generated namespace includes the name of the unit in which the interface is defined, sharing the same unit in both client and server applications enables them to automatically use the same namespace, as long as they both use the same value for the AppNamespacePrefix variable.
The preceding example uses only scalar types (integers and doubles) in the methods of the interface. You can use nonscalar types as well, but they require a bit more work.