Using Remotable Objects

From RAD Studio
Jump to: navigation, search

Go Up to Using Nonscalar Types in Invokable Interfaces


Use TRemotable as a base class when defining a class to represent a complex data type on an invokable interface. For example, in the case where you would ordinarily pass a record or struct as a parameter, you would instead define a TRemotable descendant where every member of the record or struct is a published property on your new class.

The following has been deprecated:

You can control whether the published properties of your TRemotable descendant appear as element nodes or attributes in the corresponding SOAP encoding of the type. To make the property an attribute, use the stored directive on the property definition, assigning a value of AS_ATTRIBUTE:

 property MyAttribute: Boolean read FMyAttribute write FMyAttribute stored AS_ATTRIBUTE;
 __property bool MyAttribute = {read=FMyAttribute, write=FMyAttribute, stored= AS_ATTRIBUTE;

If you do not include a stored directive, or if you assign any other value to the stored directive (even a function that returns AS_ATTRIBUTE), the property is encoded as a node rather than an attribute.

The AS_ATTRIBUTE feature has been deprecated. It still works for legacy code, but the preferred approach is to use the index value of a property. The index property allows you to specify whether a property is an attribute, an unbounded element, an optional element, a text value, or can have a value of NULL. The support for optional elements relies on the stored property attribute, which points to a method that returns TRUE if the property has been specified, FALSE if not.

The following example illustrates the support for an optional attribute and a text element:

type
{ This stores the languages that the system supports }
  Thumbnail = class(TRemotable)
  private
    FText: WideString;
    FExists: WideString;
    FExists_Specified : boolean;
    procedure SetExists(Index: Integer; _prop_val: WideString);
    function Exists_Specified(Index: Integer): boolean;

  published
    property Text: WideString index IS_TEXT read FText write FText;
    property Exists: WideString index IS_ATTR or IS_OPTN read FExists write SetExists stored Exists_Specified;
  end;

implementation

  procedure Thumbnail.SetExists(Index: Integer; _prop_val: WideString);
  begin
    FExists := _prop_val;
    FExists_Specified := true;
  end;

  function Thumbnail.Exists_Specified(Index: Integer): boolean;
  begin
    Result := FExists_Specified;
  end;
end.
 class Thumbnail : public TRemotable {
 private:
    WideString      FText;
    WideString      FExists;
    bool            FExists_Specified;
    void __fastcall SetExists(int Index, WideString _prop_val)
    {  FExists = _prop_val; FExists_Specified = true;  }
    bool __fastcall Exists_Specified(int Index)
    {  return FExists_Specified;  }
   __published:
    __property WideString       Text = { index=(IS_TEXT), read=FText, write=FText };
    __property WideString     Exists = { index=(IS_ATTR|IS_OPTN), read=FExists, write=SetExists, stored = Exists_Specified };
 };

If the value of your new TRemotable descendant represents a scalar type in a WSDL document, you should use TRemotableXS as a base class instead. TRemotableXS is a TRemotable descendant that introduces two methods for converting between your new class and its string representation. Implement these methods by overriding the XSToNative and NativeToXS methods.

For certain commonly-used XML scalar types, the XSBuiltIns unit already defines and registers remotable classes for you. These are listed in the following table:

Remotable classes :

XML type remotable class

dateTime timeInstant

TXSDateTime

date

TXSDate

time

TXSTime

durationtimeDuration

TXSDuration

decimal

TXSDecimal

hexBinary

TXSHexBinary

string

TXSString

boolean

TXSBoolean

integer

TXSInteger

long

TXSLong



Note: You can use TXSString, TXSBoolean, TXSInteger and TXSLong for cases where a string, boolean, integer, or long value can be nil (NULL or 0 for C++). You can use the type TXMLData when the data sent or received is unspecified. TXMLData can be used for passing raw XML--such as a schema--in a SOAP message.

After you define a remotable class, it must be registered with the remotable type registry, as described in Registering Nonscalar Types. This registration happens automatically on servers when you register the interface that uses the class. On clients, the code to register the class is generated automatically when you import the WSDL document that defines the type. For an example of defining and registering a remotable class, see Remotable Object Example.

Tip: It is a good idea to implement and register TRemotable descendants in a separate unit from the rest of your server application, including from the units that declare and register invokable interfaces. In this way, you can use the type for more than one interface.

Representing attachments

One important TRemotable descendant is TSoapAttachment. This class represents an attachment. It can be used as the value of a parameter or the return value of a method on an invokable interface. Attachments are sent with SOAP messages as separate parts in a multipart form.

When a Web Service application or the client of a Web Service receives an attachment, it writes the attachment to a temporary file. TSoapAttachment lets you access that temporary file or save its content to a permanent file or stream. When the application needs to send an attachment, it creates an instance of TSoapAttachment and assigns its content by specifying the name of a file, supplying a stream from which to read the attachment, or providing a string that represents the content of the attachment.

Managing the lifetime of remotable objects

One issue that arises when using TRemotable descendants is the question of when they are created and destroyed. Obviously, the server application must create its own local instance of these objects, because the caller's instance is in a separate process space. To handle this, Web Service applications create a data context for incoming requests. The data context persists while the server handles the request, and is freed after any output parameters are marshaled into a return message. When the server creates local instances of remotable objects, it adds them to the data context, and those instances are then freed along with the data context.

In some cases, you may want to keep an instance of a remotable object from being freed after a method call. For example, if the object contains state information, it may be more efficient to have a single instance that is used for every message call. To prevent the remotable object from being freed along with the data context, change its DataContext property.

See Also