Defining Code-First services (Delphi)

Supported data types

Not every Delphi data type can be used in the interface published by the Code-First server.

Only following data types are supported:

Note: Binary is a wrapper over the TMemoryStream type .

  • Boolean
  • Currency
  • DateTime (alias for TDateTime)
  • Decimal
  • Double
  • Guid

Note: String value of TGuid.

  • Integer
  • Int64
  • NullableBoolean
  • NullableCurrency
  • NullableDateTime
  • NullableDecimal
  • NullableDouble
  • NullableGuid
  • NullableInt64
  • NullableInteger
  • String

Note: String values can be serialized and deserialized in 3 different incompatible encodings: ANSI, UTF8, Unicode

Note: Published properties of these descendants should have supported data types (including other TROComplexType descendants)

  • Enumeration
  • Arrays of supported data types. Descendants of TROArray.

Service definitions

Sample Code-First service definition:

[ROService]
SampleService = class(TRORemoteDataModule)
public
  [ROServiceMethod]
  function DoSomething(someValue: String): String;
end;

A class is considered as a Code-First service definition if these conditions are met:

Note: Service should be registered with RegisterCodeFirstService method in initialization section like

initialization
  RegisterCodeFirstService(SampleService);
end.

otherwize delphi compiler will remove this service during linking

The method is considered as a published if these conditions are met:

  • The method is public
  • Method is marked with the ROServiceMethod attribute

The following restrictions are applied to the published methods:

  • Published method names should be unique
  • Method result type (if any) and method parameter types should be ones of the supported types list

If these restrictions are not met the server app will be able to compile but will throw an exception at runtime. See the Debugging Code-First servers topic for advices on pinpointing such situations.

The following attributes can be applied to the service definition:

Attribute Description
ROAbstract Marks the service as abstract. Abstract services are published in the server's RODL but cannot be called directly
ROCustom(name,value)
[required] name
[required] value
custom name/value pair attribute
RODocumentation(documentation)
[required] documentation
Sets the documentation text for the service
ROLibraryAttributes(class)
[required] class
Specifies class with additional information about RODL library
RONamespace(namespace)
[required] namespace
Specifies target namespace. ignored if ROLibraryAttributes attribute is set.
ROObsolete(message)
[optional] message
Adds obsolete or specified message to documentation
ROPerClientClassFactory(timeoutSeconds)
[required] timeoutSeconds
Sets Per-Client class factory for the incoming requests - every client will be served by a distinct service instance
ROPooledClassFactory(size,behavior,preinit)
[required] size
[optional] behavior
[optional] preinit
Sets Pooling class factory for the incoming requests - a pool of instances will be maintained to server incoming requests.
RORole(role)
[required] role
specifies service role
ROService(name,guid) required
[optional] name
[optional] guid
Identifies Code-First service.
ROServiceGroup(group)
[required] group
used for generation of reduced RODL or disabling access on server level. Check Service Group article for more details
ROServiceRequiresLogin Sets the service instance's RequiresSession property to true at runtime. Service marked with this attribute will require user to first log in
ROSingletonClassFactory Sets Singleton class factory for the incoming requests - a single service instance will be used to serve all calls
ROSkip Exclude service from generating RODL for client-side
ROStandardClassFactory Sets Per-Request class factory for the incoming requests - a new service instance will be created for each incoming request, and destroyed afterwards. used by default
ROSynchronizedSingletonClassFactory Sets Synchronized Singleton class factory for the incoming requests - a single service instance will be used to serve all calls with synchronization options for thread safety
ROZeroConfService(name)
[required] name
Specifies name for ZeroConf registartiion

The following attributes can be applied to the service method definitions:

Attribute Description
ROCustom(name,value)
[required] name
[required] value
custom name/value pair attribute
RODocumentation(documentation)
[required] documentation
Sets the documentation text for the method
ROObsolete(message)
[optional] message
Adds obsolete or specified message to documentation
RORole(role)
[required] role
specifies method role.
ROServiceMethod(name) required
[optional] name
Identifies Code-First service method.
ROServiceMethodResultName(name)
[required] name
Sets the result name of method. Used in SOAP-based services only.
ROSkip Exclude method from generating RODL for client-side
ROStreamAs(mode)
[required] mode
Sets encoding used to send string data. It affects to the result serialization. The same attribute can be applied for each string parameter

Server-Sent Events definitions

Sample Server-Sent Events interface definition:

[ROEventSink]
IIChatEvents = interface(IROEventSink)
['{3553ECAF-C4EF-4685-8109-5738661036EC}']
  procedure MessageReceived(sender: String; message: String);
end;

An interface is considered as a Code-First Server-Sent Events interface definition if these conditions are met:

  • The interface is inherited from the IROEventSink interface directly or indirectly

The following restrictions are applied to the published methods:

  • Interface method names should be unique
  • Interface methods should not return any results (i.e methods should be procedure).
  • Interface method parameter types should be ones of the supported types list
  • Interface method parameters haven't use var or out modifiers.

The following optional attributes can be applied to the event sink interface definition:

Attribute Description
ROCustom(name,value)
[required] name
[required] value
custom name/value pair attribute
RODocumentation(documentation)
[required] documentation
Sets the documentation text for the event sink
ROEventSink(name)
[optional] name
Identifies Code-First event sink
ROLibraryAttributes(class)
[required] class
Specifies class with additional information about RODL library
RONamespace(namespace)
[required] namespace
Specifies target namespace. ignored if ROLibraryAttributes attribute is set.
ROObsolete(message)
[optional] message
Adds obsolete or specified message to documentation
ROServiceGroup(group)
[required] group
used for generation of reduced RODL or disabling access on server level. Check Service Group article for more details
ROSkip Exclude service from generating RODL for client-side

The following optional attributes can be applied to the interface method definitions:

Attribute Description
ROCustom(name,value)
[required] name
[required] value
custom name/value pair attribute
RODocumentation(documentation)
[required] documentation
Sets the documentation text for the method
ROStreamAs(mode)
[required] mode
Sets encoding used to send string data. It affects to the result serialization. The same attribute can be applied for each string parameter

Structure (complex type) definitions

Sample Code-First Structure definition:

SampleStructure = class(TROComplexType)
private
  fStringProperty: String;
  fIntegerProperty: Integer;
published
  property StringProperty: String read fStringProperty write fStringProperty;
  property IntegerProperty: Integer read fIntegerProperty write fIntegerProperty;
end;

A class is considered as a Code-First Structure definition if these conditions are met:

  • The class is inherited from the TROComplexType class directly or indirectly
  • The class or any of its ancestor classes is used as data type of a parameter in a service or event interface method, or as a data type of a Structure or an Exception property

The following restrictions are applied to the class properties:

  • Indexed properties are not supported
  • Parameter data types should be ones of the supported types list
  • properties should be published
  • only read/write properties are supported

The following optional attribute can be applied to the structure definition:

Attribute Description
ROCustom(name,value)
[required] name
[required] value
custom name/value pair attribute
RODocumentation(documentation)
[required] documentation
Sets the documentation text for the struct
ROLibraryAttributes(class)
[required] class
Specifies class with additional information about RODL library
RONamespace(namespace)
[required] namespace
Specifies target namespace. ignored if ROLibraryAttributes attribute is set.

The following optional attributes can be applied to the structure properties:

Attribute Description
ROCustom(name,value)
[required] name
[required] value
custom name/value pair attribute
RODocumentation(documentation)
[required] documentation
Sets the documentation text for the property
ROStreamAs(mode)
[required] mode
Sets encoding used to send string data. It affects to the property serialization.

Enumeration definitions

Sample Code-First enumeration definition:

SampleEnum = (First, Second, Third);

An enum is considered as a valid Code-First Enum definition if these conditions are met:

  • The enum element values start from 0 and are sequential.
  • The enum is used as data type of a parameter in a service or event interface method, or as a data type of a Structure or an Exception property

The following optional attribute can be applied to the enum definition:

Attribute Description
ROCustom(name,value)
[required] name
[required] value
custom name/value pair attribute
RODocumentation(documentation)
[required] documentation
Sets the documentation text for the enum
ROEnumSoapName(name,soapname)
[required] name
[required] soapname
allows to specify soap name of given enum
ROLibraryAttributes(class)
[required] class
Specifies class with additional information about RODL library
RONamespace(namespace)
[required] namespace
Specifies target namespace. ignored if ROLibraryAttributes attribute is set.

No attributes can be applied to the enum elements.

ROEnumSoapName attribute can be used as

  [ROEnumSoapName('First', 'soapFirst')]
  [ROEnumSoapName('Second', 'soapSecond')]
  [ROEnumSoapName('Third', 'soapThird')]  
  SampleEnum = (First, Second, Third);

Exception definitions

Sample Code-First exception:

SampleException = class(EROServerException)
private
  fAdditionalData: String;
published
  property AdditionalData: String read fAdditionalData write fAdditionalData;
end;

A class is considered as a Code-First Exception definition if these conditions are met:

  • The class is inherited from the EROServerException class directly or indirectly
  • exception should be used/raised somewhere in code otherwize delphi compiler will remove it during linking

The following restrictions are applied to the class properties:

  • Indexed properties are not supported
  • Parameter data types should be ones of the supported types list

The following optional attribute can be applied to the exception definition:

Attribute Description
ROCustom(name,value)
[required] name
[required] value
custom name/value pair attribute
RODocumentation(documentation)
[required] documentation
Sets the documentation text for the exception
ROLibraryAttributes(class)
[required] class
Specifies class with additional information about RODL library
RONamespace(namespace)
[required] namespace
Specifies target namespace. ignored if ROLibraryAttributes attribute is set.

The following optional attributes can be applied to the exception properties:

Attribute Description
ROCustom(name,value)
[required] name
[required] value
custom name/value pair attribute
RODocumentation(documentation)
[required] documentation
Sets the documentation text for the property
ROStreamAs(mode)
[required] mode
Sets encoding used to send string data. It affects to the property serialization.