Everything seems to work fine. However, very rarely, we encounter the following error:
BinMessage: Unexpected end of stream.
With the following stack trace:
at RemObjects.SDK.BinSerializer.ReadInt32()
at RemObjects.SDK.BinSerializer.ReadBoolean(String name)
at RemObjects.SDK.Message.ReadBoolean(String name)
at ..ProjectManagerWebService.ProjectManagerService_Proxy.GetDevicesByProjectId(String projectId, Binary& deviceList, String& vErrorDesc)
We are using multiple threads within our application, so I’m wondering if the call to __GetMessage() is returning a common object, that would ultimately be shared by multiple threads. If that’s the case, then I could see how multiple threads all making service operation calls simultaneously could result in a conflict - and eventually an odd exception.
Shouldnt this change be applied to the Delphi side of things?
Looking at the code generated I think the synchronous versions TROPROXY when created passing a channel and a message (as we do ours) creates them without clonning it. The ones created using a IRORemoteService clones them or not depending on the message setting as it should be.
fCloneMessage parameter is used in __GetMessage method:
function TROProxy.__GetMessage: IROMessage;
begin
if fCloneMessage then
Result := (__Message as IROMessageCloneable).Clone
else
Result := __Message;
end;
I’m confused on how this works and correct me if im mistaken, the only place where a developer can access and alter the property CloneMessage is on the TRORemoteService class. But If Im not using that class and I’m creating the proxy via a URI or specifying directly the transport and channel (as seen on uROBaseProxy) the fCloneMessage private property is set to false by default as seen above and as you mentioned everything else works based on this private property.
So you can just set CloneMessage to true so the message object will always be cloned. For async service proxies the message object is cloned always.
I’ll log an issue to double-check and ensure that the CloneMessage is set to true by default for sync service proxies as well.
Shouldnt we have that option set by default to true as Anton is saying he did on all the generated proxies? Is there a harm on not doing so? It is not very obvious for the average user that you have to cast an interface on the instance and then call a function and pass it to the create proxy to be able to make it work.
I only see the positive side, but probably Im missing the negative, what problems will cause to have it on true by default on the other options?
Looking at the code it seems that the intended purpose was to actually use the fCloneMessage property for all circumstances as a flag for message cloning instead of creating a clone of the message and pass it as part of the constructor.
We built highly threaded systems with hundred thousands of requests/messages, etc, concurrency issues are common. Anything to alleviate them helps. But again, I dont know if the message ids are kept or other variables that could mess things up.
cloned message takes owner’s properties, because it calls Assign:
function TROMessage.Clone: IROMessage;
begin
result := TROMessageClass(ClassType).CreateRefCountedClone(self) as IROMessage;
end;
constructor TROMessage.CreateRefCountedClone(iMessage: TROMessage);
begin
Create();
fReferenceCounted := True;
Assign(iMessage);
end;