You are not logged in.
Pages: 1
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
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
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
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
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
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
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
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
Ok.
Thank you, I will test with this modification on the framework.
Offline
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
Hello TPlachta !
Can you provide me with the sample of your TStringlist both on Server and clientside
Thanks
Cybertrace
Offline
Pages: 1