Defining Code-First services (Delphi)
Table of contents
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:
- Binary (alias for TROBinaryMemoryStream)
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
- Variant
- IXmlNode
- Descendants of TROComplexType
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:
- The class is inherited from the TRORemoteDataModule or TRORemotable class directly or indirectly
- The class is marked with the ROService attribute
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. |