Delphi 2009 introduced support for DataSnap server methods. If you are not familiar with this feature, here are two articles that describe server methods: DataSnap 2009 Overview , Getting Started with Delphi DataSnap 2009.
DataSnap server methods support a variety of parameter and return types. The following list shows the types grouped into my own categories.
This post is about "Basic" types. The sample client and server projects that go with this post can be downloaded here: http://cc.codegear.com/item/26702
| Basic | DBXValue | Collection | Connection |
|---|---|---|---|
|
|
|
|
Getting Started with Delphi DataSnap 2009 uses the following function as an example of a server method:
function TDSServerModule1.Echo(s: string): string; begin Result := 'Delphi DataSnap 2009 is echoing ' + s + ' ....' + s; end;
The proxy generator generates the following code to call this method:
function TDSServerModule1Client.Echo(s: string): string;
begin
if FEchoCommand = nil then
begin
FEchoCommand := FDBXConnection.CreateCommand;
FEchoCommand.CommandType := TDBXCommandTypes.DSServerMethod;
FEchoCommand.Text := 'TDSServerModule1.Echo';
FEchoCommand.Prepare;
end;
FEchoCommand.Parameters[0].Value.SetWideString(s);
FEchoCommand.ExecuteUpdate;
Result := FEchoCommand.Parameters[1].Value.GetWideString;
end;
I wanted my sample server and client to work like the sample in the article, with simple server methods and generated proxy in the client. In addition, I wanted to support various types so started with this generic server method implementation:
{$METHODINFO ON}
TTestBasicType = class(TComponent)
function Echo(I: T): T;
end;
{$METHODINFO OFF}
function TTestBasicType.Echo(I: T): T;
begin
Result := I;
end;
The I used TTestBasicType used to declare and implement "Echo" methods for a variety of types, such as string, boolean, and double:
TTestString = class(TTestBasicType<string>)) end; TTestBoolean = class(TTestBasicType<Boolean>) end; TTestDouble = class(TTestBasicType<Double>)) end;
To test parameters directions, I expanded the generic class with var and out parmeters:
{$METHODINFO ON}
TTestBasicType = class(TComponent)
function Echo(I: T): T;
procedure Copy(I: T; out J: T);
procedure Swap(var I: T; var J: T);
end;
{$METHODINFO OFF}
Consult the sample server to see how I’ve implemented the "plumbing" to make these classes callable by a DataSnap client. The implementation is unconventional because the TDSServerClass component is not used.
The sample VCL client is built starting with a TSQLConnection component. After setting the port and host name, I right clicked on the TSQLConnection and selected "Generate DataSnap client classes" to generate a client proxy:
In the generated code, there is a "Client" class for every one of the server classes. For example, TTestBooleanClient calls the TTestBoolean class on the server:
TTestBooleanClient = class private FDBXConnection: TDBXConnection; FInstanceOwner: Boolean; FEchoCommand: TDBXCommand; FCopyCommand: TDBXCommand; FSwapCommand: TDBXCommand; public constructor Create(ADBXConnection: TDBXConnection);overload; constructor Create(ADBXConnection: TDBXConnection; AInstanceOwner: Boolean); overload; destructor Destroy; override; function Echo(I: Boolean): Boolean; procedure Copy(I: Boolean; out J: Boolean); procedure Swap(var I: Boolean; var J: Boolean); end;
Here is the implementation of TTestBooleanClient.Echo. Consult the sample code to see the complete proxy implementation.
function TTestBooleanClient.Echo(I: Boolean): Boolean; begin if FEchoCommand = nil then begin FEchoCommand := FDBXConnection.CreateCommand; FEchoCommand.CommandType := TDBXCommandTypes.DSServerMethod; FEchoCommand.Text := 'TTestBoolean.Echo'; FEchoCommand.Prepare; end; FEchoCommand.Parameters[0].Value.SetBoolean(I); FEchoCommand.ExecuteUpdate; Result := FEchoCommand.Parameters[1].Value.GetBoolean; end;
The sample client tests the generated methods by calling them with sample values and verifying the results. Consult the sample for implementation details.
Here is screen shot of the running server and client:
The following table shows the parameter types and return types demonstrated in the sample client and server:
| Type | (in) | var | out | Result |
|---|---|---|---|---|
| AnsiString | X | X | ||
| Boolean | X | X | X | X |
| Currency | X | X | X | X |
| TDateTime | X | X | X | X |
| DBXDate | X | X | X | X |
| DBXTime | X | X | X | X |
| Double | X | X | X | X |
| Int64 | X | X | X | X |
| Integer | X | X | X | X |
| LongInt | X | X | X | X |
| OleVariant | X | X | X | |
| Single | X | X | X | X |
| SmallInt | X | X | X | X |
| String | X | X | ||
| WideString | X | X |
There are some Delphi types that you might expect to see in this list such as Byte and Cardinal. DataSnap currently doesn’t support these two nor LongWord, ShortInt, Word, TSQLTimeStamp, and TBcd. Support for var and out strings is coming (a workaround/alternative is to use TDBXStringValue in place of var String and TDBXAnsiStringValue in place of var AnsiString).
Thats all for now. I plan to cover more types in the future.

{ 4 } Comments
Jim, most interesting and very valuable post.
Many thanks
Robert
Dear Sir.
When I run the application on my machine,there is an error messagebox on the client side,whitch tells me that : ”1/1/2000 12:01:01” is not a valid date and time.
Why……..?
jz,
The string passed to StrToDateTime doesn’t match your locale.
Change these lines:
LValue1 := StrToDateTime(’1/1/2000 12:01:01′);
LValue2 := StrToDateTime(’12/31/1999 11:02:02′);
To
LValue1 := EncodeDateTime(2000, 1, 1, 12, 1, 1, 0);
LValue2 := EncodeDateTime(1999, 12, 31, 11, 2, 2, 0);
How would you implment a function where you need to pass a complex user defined data type, such as collection of parameters?
Post a Comment