#1 2016-04-25 08:41:27

TPlachta
Member
Registered: 2016-04-25
Posts: 7

Error sendind TStringList from Client to Server

Hi.

I'm trying tu use mORMot framework in order to make a client/server application, but I got an issue when trying to send an object as an input paramter that contains a TStringList property.


Here is my test class to send TStringList to server:

  TolTest = Class(TCollectionItem)
  private
    FChaine: String;
    FListe: TStringList;
  public
    constructor Create(aCollection: TCollection); override;
    destructor Destroy; override;
  published
    property Chaine : String read FChaine write FChaine;
    property Liste : TStringList read FListe write FListe;
  End;

The constructor do an inherited and call TStringList.Create to instantiate the FListe.

I Also do in the initialization section of my unit containing my class :

  TJSONSerializer.RegisterClassForJSON(TolTest); 

The interface looks like this :

 
  IBanqueDeScriptService = interface(IInvokable)
    ['{21BAC477-1979-4FE4-A45D-067B11E8483C}']
    procedure SendTest(aTest : TolTest);
  end;

And when I call the interface's procedure on the client side, i got this error :

errorCode : 406
errorText : (sicSingle) execution failed (probably due to bad input parameters)

I tried to send a TPersistend without TStringList property, it's ok.
I tried to send a TCollectionItem without TStringList, also ok.
When I add the TStringList property, it's impossible to send the object from the client to the server.

But, it's possible to send the same object as an output parameter, so the server is able to parse the object and send it back to the client.

Do you have an idea of what I did wrong ?

Offline

#2 2016-04-25 10:26:10

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,220
Website

Re: Error sendind TStringList from Client to Server

IMHO RegisterClassForJSON() is not needed at all here.

Which version of Delphi are you using?

You have to follow the documentation for TCollection.
See http://synopse.info/files/html/Synopse% … ml#TITL_55

Offline

#3 2016-04-25 12:17:15

TPlachta
Member
Registered: 2016-04-25
Posts: 7

Re: Error sendind TStringList from Client to Server

I use Delphi 10 Seattle.

In fact, if I do things like this :

  TolTest = Class(TCollectionItem)
  private
    FChaine: String;
  public
    constructor Create(aCollection: TCollection); override;
    destructor Destroy; override;
  published
    property Chaine : String read FChaine write FChaine;
  End;

  TolTests = Class(TInterfacedCollection)
  protected
    class function GetClass: TCollectionItemClass; override;
  End;

I can send an instance of TolTest as a input parameter of my service.

But, if I want to add a TPersistent on my item TolTest, I got the issue.

If I do so :

TolChild = class(TPersistent)
  private
    FNom: String;
  published
    property Nom : String read FNom write FNom;
  end;

  TolTest = Class(TCollectionItem)
  private
    FChaine: String;
    FChild : TolChild;
  public
    constructor Create(aCollection: TCollection); override;
    destructor Destroy; override;
  published
    property Chaine : String read FChaine write FChaine;
    property Child : TolChild read FChild write FChild;
  End;

  TolTests = Class(TInterfacedCollection)
  protected
    class function GetClass: TCollectionItemClass; override;
  End;

I'm not able to send my TColTest from client to server

Offline

#4 2016-04-25 12:51:02

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,220
Website

Re: Error sendind TStringList from Client to Server

What is the JSON sent from the client to the server?

Use the IDE debugger to find out what's wrong.

Offline

#5 2016-04-25 13:11:02

TPlachta
Member
Registered: 2016-04-25
Posts: 7

Re: Error sendind TStringList from Client to Server

I build my item like this :

  lTest := TolTest.Create(nil);
  lTest.Chaine := 'Blacksheep wall';
  lTest.Child.Nom := 'StarCraft'; // The property FChild of the TolTest is created and destroyed by the constructor and destructor of the TolTest
  FBanqueDeScript.SendTest(lTest);

If I put a breakpoint on mORMot.pas, in FakeCall.InternalProcess, the value of "ParamsJSON" is

 {"Chaine":"Blacksheep wall","Child":{"Nom":"StarCraft"}} 

And in the TServiceFactoryClient.InternalInvoke, the value of "sent" is

 [{"Chaine":"Blacksheep wall","Child":{"Nom":"StarCraft"}}] 

Offline

#6 2016-04-25 13:14:23

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,220
Website

Re: Error sendind TStringList from Client to Server

Now check on the server side.

Or just with ObjectToJson and JSONToObject functions.

Offline

#7 2016-04-25 13:43:23

TPlachta
Member
Registered: 2016-04-25
Posts: 7

Re: Error sendind TStringList from Client to Server

On server side, I proceeded like this for testing :

I added a procedure  GetTest(out aTest : TolTest) in my interface.

procedure TomBanqueDeScript.GetTest(out aTest: TolTest);
begin
  aTest.Chaine := 'Blacksheep wall';
  if not Assigned(aTest.Child) then
    aTest.Child := TolChild.Create(nil);

  aTest.Child.Nom := 'StarCraft';
end;

Doing this, I have noticed one thing : the object property of my object is NIL on the server side when I call the procedure GetTest from client side, whereas I create it on the constructor of my TolTest.
So i need to create it by myself on the server side if i want to use it.
When the server answers, in the TServiceMethodExecute.ExecuteJson, the value of Res.TempBuf is :

 
  {"result":[{Chaine:"Blacksheep wall",Child:{Nom:"StarCraft"}},7AD54749BB83E8"]} 253623 Request"'#$D#$A'}
     cript\Server\Win32\Debug\srvBanqueDeScript.exe 1.0.0.0 (2016-04-25 15:29:45) '#1'C'
 

Offline

#8 2016-04-25 15:16:57

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,220
Website

Re: Error sendind TStringList from Client to Server

On the server side, the "out aTest" parameter has been instantiated by the framework.

Put a breakpoint on server side in mORMot.pas' JsonToObject() function:

CollItem := Coll.Add;

Here your constructor should be called.

Offline

#9 2016-04-25 16:03:28

TPlachta
Member
Registered: 2016-04-25
Posts: 7

Re: Error sendind TStringList from Client to Server

I put a breakpoint in mORMot.pas on the server side, at the begining of the procedure, but it does not pass in.

In the stack I see :

srvBDS_.TomBanqueDeScript.GetTest($17D55A0)
:007cca7b CallMethod + $27
mORMot.CallMethod(???)
mORMot.TServiceMethodExecute.RawExecute($420F838,0)
mORMot.TServiceMethodExecute.ExecuteJson((...),'[]',$17FFB80,False)
mORMot.TServiceFactoryServer.ExecuteMethod($170A350)
mORMot.ComputeResult
mORMot.TSQLRestServerURIContext.InternalExecuteSOAByInterface
mORMot.TSQLRestRoutingREST.ExecuteSOAByInterface
mORMot.TSQLRestServerURIContext.ExecuteCommand
mORMot.TSQLRestServer.URI($420FBF8)
mORMotHttpServer.TSQLHttpServer.Request($1832460)
SynCrtSock.THttpServerGeneric.Request($1832460)
SynBidirSock.TWebSocketProtocolRest.ProcessIncomingFrame($178C0A0,(focBinary, ''),'')
SynBidirSock.TWebSocketProtocolBinary.ProcessIncomingFrame($178C0A0,(focBinary, ''),'')
SynBidirSock.TWebSocketProcess.ProcessLoop
SynBidirSock.TWebSocketServer.WebSocketProcessUpgrade($40074E8,$1806AC8)
SynBidirSock.TWebSocketServer.Process($40074E8,1,$1806AC8)
SynCrtSock.HandleRequestsProcess
SynCrtSock.THttpServerResp.Execute
System.Classes.ThreadProc($1806AC8)
System.ThreadWrapper($17E2AA0)

And, in the "mORMot.TServiceMethodExecute.ExecuteJson((...),'[]',$17FFB80,False)", JSONToObject is called for object parameters only if not in smdOut direction.
So in the case of the GetTest method (used to test the serialization on the server side), the parameter is an output parameter.

Furthermore, the property "FChild" of my TolTest is an object, not a collection, so in the JSONToObject, it will not pass in the oCollection section ?

Offline

#10 2016-04-25 22:18:05

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,220
Website

Re: Error sendind TStringList from Client to Server

I thought you were passing the TolTests collection, not the TolTest item, to the service.
My mistake.

In this case, it does make sense that your overriden constructor was not called.
A plain collection is not expected to be transmitted without its collection.

I've added TCollectionItem class recognition in TClassInstance.
Your custom overriden constructor should be called now.
See http://synopse.info/fossil/info/5152aca474

But, to be honest, I would never use a TCollectionItem as a value object, but rather use T*ObjArray kind of properties, which get rid of the TCollection overhead.

Offline

#11 2016-04-26 06:56:34

TPlachta
Member
Registered: 2016-04-25
Posts: 7

Re: Error sendind TStringList from Client to Server

Ok.

Thank you, I will test with this modification on the framework.

Offline

#12 2016-04-26 07:09:23

TPlachta
Member
Registered: 2016-04-25
Posts: 7

Re: Error sendind TStringList from Client to Server

Thank you again for this modification, it's work fine.

I can send an object contaning a TCollectionItem and/or a TStringList from my client to my server.

Offline

#13 2016-04-27 10:00:59

cybertrace
Member
Registered: 2016-02-29
Posts: 15

Re: Error sendind TStringList from Client to Server

Hello TPlachta !

Can you provide me with the sample of your TStringlist both on Server and clientside

Thanks

Cybertrace

Offline

Board footer

Powered by FluxBB