Defining Code-First services (.NET)

Supported data types

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

Only following data types are supported:

  • RemObjects.SDK.Binary (this is a wrapper over the System.IO.MemoryStream type)
  • Boolean
  • DateTime
  • Decimal
  • Double
  • Guid
  • Int32
  • Int64
  • String. String values can be serialized and deserialized in 3 different incompatible encodings:

    • ANSI
    • UTF8
    • Unicode (compatible with the Delphi WideString data type)

  • System.Xml.XmlNode
  • Object. List of supported value types of Object-typed parameters or properties is very limited:

    • null
    • System.Boolean
    • System.Byte
    • System.SByte
    • System.DateTime
    • System.Decimal
    • System.Double
    • System.Int16
    • System.Int32
    • System.Int64
    • System.String (serialized using the UTF8 encoding)
    • System.Guid

  • Class inherited from RemObjects.SDK.ComplexType. Public properties of classes inherited from RemObjects.SDK.ComplexType should have supported data types (including other ComplexType descendants)
  • Enumeration
  • Arrays of supported data types

Service definitions

Sample Code-First service definition:

[Service] 
public class SampleService : RemObjects.SDK.Server.Service 
{ 
    [ServiceMethod] 
    public string DoSomething(string someValue) 
    { 
        return "No Result"; 
    } 
} 
[Service]
SampleService = public class(RemObjects.SDK.Server.Service)
public
  [ServiceMethod]
  method DoSomething(someValue: String): String;
end;
@Service open class SampleService : RemObjects.SDK.Server.Service { 
    @ServiceMethod 
    public func DoSomething(someValue: String!) -> String! {
        return "No Result"
    }
}

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

  • The class is inherited from the RemObjects.SDK.Server.Service class directly or indirectly
  • The class is marked with the Service attribute
  • The class is public

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

  • The method is public
  • Method is marked with the ServiceMethod 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 Cofe-First servers topic for advices on pinpointing such situations.

The following optional attributes can be applied to the service definition:

Attribute Description
ServiceRequiresLogin Sets the service instance's RequiresSession property to true at runtime. Service marked with this attribute will require user to first log in
RemObjects.SDK.Server.ClassFactories.StandardClassFactory RemObjects.SDK.Server.ClassFactories.PerClientClassFactory RemObjects.SDK.Server.ClassFactories.SingletonClassFactor Defines a class factory that will be used to instantiate the service instances to server the incoming requests. By default the Standart class factory is used
Abstract Marks the service as abstract. Abstract services are published in the server's RODL but cannot be called directly
Documentation Sets the documentation text for the service

The required Service attribute has an optional Name parameter that can be used to alter the name that is used to publish the service:

[Service(Name = "NewServiceName")]

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

Attribute Description
StreamAs Sets encoding used to send string data. Can be applied to method or its parameters. When applied to the method - this attribute affects the method result serialization. This attribute is ignored for any non-string parameters
Documentation Sets the documentation text for the service method or its parameters. Can be applied to method or its parameters

The required ServiceMethod attribute has an optional Name parameter that can be used to alter the name that is used to publish the service:

[ServiceMethod(Name = "NewMethodName")] 

Asynchronous Service Methods

Starting with April 2021 releases Remoting SDK also provides support for service methods that use Task-based asynchronous pattern. This support is available for .NET Core, .NET 5+ and .NET Standard builds of Remoting SDK.

[Service] 
public class SampleService : RemObjects.SDK.Server.Service 
{
    [ServiceMethod]
    public async Task<string> DoSomething(string someValue)
    {
        var result = await ApiMethodAsync(someValue);
        return result;
    }
}

Asynchronous methods are represented in the server RODL similar to the usual synchronous methods and do not require client platforms to support Task-based asynchronicity.

Server-Sent Events definitions

Sample Server-Sent Events interface definition:

[EventSink] 
public interface IChatEvents : IROEventSink 
{ 
    void MessageReceived(string sender, string message); 
} 
[EventSink]
IChatEvents = public interface(IROEventSink)
  method MessageReceived(sender: String; message: String);
end;
@EventSink open protocol IChatEvents : IROEventSink { 
    func MessageReceived(_ sender: String!, _ message: String!)
}

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

  • The interface is inherited from the RemObjects.SDK.IROEventSink interface directly or indirectly
  • The interface is marked with the EventSink attribute
  • The interface is public

The following restrictions are applied to the published methods:

  • Interface Method names should be unique
  • Interface methods should not return any results (i.e their result type should be void).
  • Interface method parameter types should be ones of the supported types list

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

Attribute Description
Documentation Sets the documentation text for the events interface

The required EventSink attribute has an optional Name parameter that can be used to alter the name that is used to publish the service:

[EventSink(Name = "NewEventsName")] 

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

Attribute Description
StreamAs Sets encoding used to send string data. Can be applied to method parameters. This attribute is ignored for non-string parameters
Documentation Sets the documentation text for the interface method or its parameters. Can be applied to method or its parameters

Structure (complex type) definitions

Sample Code-First Structure definition:

public class SampleStructure : ComplexType 
{ 
    public string StringProperty { get; set; } 
    public int IntegerProperty { get; set; } 
} 
SampleStructure = public class(ComplexType)
public
  property StringProperty: String read write;
  property IntegerProperty: Integer read write;
end;
open class SampleStructure : ComplexType { 
    public var StringProperty: String! 
    public var IntegerProperty: Int32 
}

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

  • The class is inherited from the RemObjects.SDK.Types.ComplexType 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 class is public

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 structure definition:

Attribute Description
Documentation Sets the documentation text for the structure

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

Attribute Description
StreamAs Sets encoding used to send string data. This attribute is ignored for non-string properties
Documentation Sets the documentation text for property

Enumeration definitions

Sample Code-First enumeration definition:

public enum SampleEnum 
{ 
    First, 
    Second, 
    Third 
}
SampleEnum = public enum (First, Second, Third);
open enum SampleEnum { 
    case First
    case Second
    case 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. Enum with directly set element values (including Flag enums) are not supported
  • 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 enum is public

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

Attribute Description
Documentation Sets the documentation text for the enumeration definition

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

Attribute Description
Documentation Sets the documentation text for the enumeration element

Exception definitions

Sample Code-First exception:

public class SampleException : ServerException 
{ 
    public string AdditionalData { get; set; } 
} 
SampleException = public class(ServerException)
public
  property AdditionalData: String read  write ;
end;
open class SampleException : ServerException { 
    public var AdditionalData: String! 
}

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

  • The class is inherited from the RemObjects.SDK.Types.ServerException class directly or indirectly
  • The class is public

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
Documentation Sets the documentation text for the exception

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

Attribute Description
StreamAs Sets encoding used to send string data. This attribute is ignored for non-string properties
Documentation Sets the documentation text for property