You are not logged in.
Hi,
either there's a serious bug when passing TRawUTF8DynArray parameters throug service interfaces, or i'm doing something wrong.
In my interface, I have a function like "function GetData(arr: TRawUTF8DynArray): boolean".
arr contains RawUTF8 values which were encoded using ObjectToJSON(someSQLRecord). When retrieving the array on client-side, the JSON data is broken.
eg. :
Before sending data arr[0] contains:
{"ID":1,"Title":"Mr.","Name":"Pablo"}
when received, arr[0] contains:
{"ID 1 "Title "Mr. "Name "Pablo "
What should I do???
Please help!
Edit:
If I pass arr[0] as a simple RawUTF8, it works fine.
How can I pass a list/array of JSON encoded RawUTF8 Strings to the client?
Last edited by xotox (2015-02-25 08:50:32)
Offline
I can not use GetData(const arr: TRawUTF8DynArray), because "arr" is filled by server, then sent to client. Sever has to call SetLength(arr) etc.
I'll provide a demo asap.
Thanks.
Offline
Maybe you should use GetData(out arr: TRawUTF8DynArray) if the server side fill with data.
Esteban
Offline
Maybe you should use GetData(out arr: TRawUTF8DynArray) if the server side fill with data.
Thats exactly how it's implemented right now.
Well I just wrote a test to show the problem, but the Test works as expected!
As far as I can see, the test is doing exactly the same thing my real project does. I'm speechless.
???
Well, here's the Testcode:
program Test;
{$APPTYPE CONSOLE}
uses
FastMM4,
SynSQLite3Static,
SysUtils,
SynCommons,
SynSQLite3,
mORMot,
mORMotSQLite3,
mORMotHTTPServer,
mORMotHTTPClient;
type
IMyInterface = interface(IInvokable)
['{1A664CAB-BD0E-44B3-BB5F-5CAEB425FDB3}']
procedure GetData(out Arr: TRawUTF8DynArray; out Arr2: TRawUTF8DynArray; out S: RawUTF8);
end;
TMyInterface = class(TInterfacedObject, IMyInterface)
public
procedure GetData(out Arr: TRawUTF8DynArray; out Arr2: TRawUTF8DynArray; out S: RawUTF8);
end;
TSQLRecordBase=class(TSQLRecord)
private
fAProp: RawUTF8;
published
property AProp: RawUTF8 read fAProp write fAProp;
end;
TSQLPerson = class(TSQLRecordbase)
private
fFirstname: RawUTF8;
fLastname: RawUTF8;
published
property Firstname: RawUTF8 index 80 read fFirstname write fFirstname;
property Lastname: RawUTF8 index 80 read fLastname write fLastname;
end;
TmyServer = class
private
fModel: TSQLModel;
fRestServer: TSQLRestServerDB;
fHTTPServer: TSQLHttpServer;
public
constructor Create;
destructor Destroy; override;
end;
TmyClient = class
private
fHTTPClient: TSQLHttpClient;
fModel: TSQLModel;
fmyInterface: ImyInterface;
public
constructor Create;
destructor Destroy; override;
procedure TestIt;
end;
function CreateModel: TSQLModel;
begin
result := TSQLModel.Create([TSQLPerson]);
end;
{ TMyInterface }
procedure TMyInterface.GetData(out Arr: TRawUTF8DynArray; out Arr2: TRawUTF8DynArray; out S: RawUTF8);
const
count = 10;
var
i: integer;
person: TSQLPerson;
begin
person := TSQLPerson.Create;
try
SetLength(Arr, count);
SetLength(Arr2, count);
for i:=Low(Arr) to High(Arr) do begin
person.Firstname := FormatUTF8('Firstname #%', [i]);
person.Lastname := FormatUTF8('Lastname #%', [i]);
Arr[i] := ObjectToJSON(person);
Arr2[i] := ObjectToJSON(person);
end;
S := Arr[0];
finally
person.Free;
end;
end;
{ TmyServer }
constructor TmyServer.Create;
begin
fModel := CreateModel;
fRestServer := TSQLRestServerDB.Create(fModel, ChangeFileExt(ParamStr(0), '.db'), true);
with fRestServer do begin
DB.Synchronous := smNormal;
DB.LockingMode := lmExclusive;
CreateMissingTables;
ServiceRegister(TmyInterface, [TypeInfo(ImyInterface)], sicClientDriven);
end;
fHTTPServer := TSQLHttpServer.Create('8080', fRestServer, '+', useHttpApiRegisteringURI);
end;
destructor TmyServer.Destroy;
begin
fHTTPServer.Free;
fRestServer.Free;
fModel.Free;
end;
{ TmyClient }
constructor TmyClient.Create;
begin
fModel := CreateModel;
fHTTPClient := TSQLHttpClient.Create('127.0.0.1', '8080', fModel);
fHTTPClient.SetUser('Admin', 'synopse');
fHTTPClient.ServiceRegisterClientDriven(TypeInfo(ImyInterface), fmyInterface);
end;
destructor TmyClient.Destroy;
begin
fmyInterface := nil;
fHttpClient.Free;
fModel.Free;
end;
procedure TmyClient.TestIt;
var
arr, arr2: TRawUTF8DynArray;
s: RawUTF8;
//person: TSQLPerson;
i: integer;
begin
fmyInterface.GetData(arr, arr2, s);
writeln(Format('Length(arr): %d', [Length(arr)]));
if (s=arr[0]) then
writeln(s=arr[0])
else begin
writeln(s);
writeln(arr[0]);
end;
for i:=Low(arr) to high(arr) do
writeln(arr[i]);
for i:=Low(arr2) to high(arr2) do
writeln(arr2[i]);
end;
var
myServer: TmyServer;
myClient: TmyClient;
begin
myServer := TmyServer.Create;
myClient := TmyClient.Create;
try
myClient.TestIt;
readln;
finally
myClient.Free;
myServer.Free;
end;
end.
Last edited by xotox (2015-02-25 14:10:56)
Offline
In my interface, I have a function like "function GetData(arr: TRawUTF8DynArray): boolean".
In the "arr" parameter is not defined any type, neither const, neither var or out.
Esteban
Offline
Ok guys, sorry for making trouble! The problem was sitting in front of the Monitor
In a quite deeply nested procedure inside the client was a code like:
for x:=Low(a1) to High(a1) do pers.FillFrom(Pointer(a1[x]));
instead of:
for x:=Low(a1) to High(a1) do pers.FillFrom(a1[x]);
Using Pointer(a1[x]) in FillPrepare changes the TRawUTF8DynArray content to:
{"ID 0 "Firstname "Firstname 0 "Lastname "Firstname 0
{"ID 0 "Firstname "Firstname 1 "Lastname "Firstname 1
{"ID 0 "Firstname "Firstname 2 "Lastname "Firstname 2
{"ID 0 "Firstname "Firstname 3 "Lastname "Firstname 3
{"ID 0 "Firstname "Firstname 4 "Lastname "Firstname 4
{"ID 0 "Firstname "Firstname 5 "Lastname "Firstname 5
{"ID 0 "Firstname "Firstname 6 "Lastname "Firstname 6
{"ID 0 "Firstname "Firstname 7 "Lastname "Firstname 7
{"ID 0 "Firstname "Firstname 8 "Lastname "Firstname 8
{"ID 0 "Firstname "Firstname 9 "Lastname "Firstname 9
Thats's it.
But thanks for your help!!!
Offline