You are not logged in.
Hi Arnaud, I'm trying to implement automatic updates to my client apps. I have a method the client calls to check if it needs to download an update. The problem is that when I make an update to my server version to add some new functionality, it breaks the clients from communicating with the server even though of course I ensure that my changes are only ever additive.
How do I turn off the checking of contract between client and server to allow the client make calls to a new server that has additional methods?
Thanks in advance
Paul
Debug Output: 21:25:23 294 Error in TClientToServer.doConnect: Server's ERefServerInterface contract differs from client's: expected ["107924CEE69317C3"], received ["4FD82C7AF11DB892"] Process eRefer.exe (4488)
Offline
You have a aContractExpected optional parameter on both client and server sides constructors which allow a custom fixed signature like a version number.
It was designed for your exact purpose.
Offline
Hi Arnaud, thanks for the quick response.
That is great news that I can provide an optional parameter to override this default behaviour. I just want to double-check - I never want a client to get a rejection from a server as the server should always be backwards compatible so does that mean that I should just hard code a static value into that optional parameter and never change it? If I used a version number, I would have thought that when I update the version number of the server that any clients calling passing a different value in that optional parameter would fail is it does now if the interface is updated?
Also, I would like it if the server could support a test and production version of the interface concurrently. Can I configure a single service to support two interfaces concurrently or have two services running alongside each other on same IP and port but responding to different interfaces?
Regards
Paul
Offline
Yes, in your case, the version number should be a "major" version number, which may break only in case of major change on the server interface, e.g. when it becomes non backwards compatible.
Interfaces are set on code level, from its type information.
So you would have to register two interfaces with diverse names and GUIDs on the same server.
Just rename one as "IMyInterfaceOld" or "IMyInterfaceDebug" and use it instead of "IMyInterface".
You can even inherit interfaces, so code duplication could be minimized: inheritance can be the lead to interface versioning.
Offline
Great, I'm sorted on the optional parameter - it must never be backwards compatible (or otherwise the client could never download the new version from the server) so I will make that parameter a constant value.
With the Production and Test versions, I think that gives me the information I need. I still need to ponder how best to use it to give me the functionality I require but as always you've given me the tools to implement what I need.
Regards
Paul
Offline
Arnaud, I have been able to add the ContractExpected parameter on the client side but I can't see how to specify it on the server side?
My server side is:
aModel := TSQLModel.Create([],ROOT_NAME);
try
aServer := TSQLRestServerFullMemory.Create(aModel,FILE_NAME,false,true);
try
aServer.ServiceRegister(TServiceERefServer,[TypeInfo(IERefServerInterface)],sicShared);
aHTTPServer := TSQLite3HttpServer.Create(COMMS_PORT,[aServer]);
How do I specify the ContractExpected on the server side?
Paul
Offline
Hi Arnaud, that's not that helpful
I spent an hour looking through the code for it last night - I wouldn't ask if I could just find the property and that is why I included the code I'm using. I can see there is a property for a different version of the ServiceRegister procedure but it is not present for the version I'm using here based on your example code.
Is this a new property you've added? The version of your code I have to use is about 6 months old.
If you can show me which server side method I need to use with the property I can move on with getting this project finished.
Thanks
Paul
Offline
The property is in TServiceFactory.ContractExpected.
So when call aRestServer.ServiceRegister(....).ContractExpected := 'MyVersion';
I'll add the parameter at constructor level for all TServiceFactory.Create() versions, for consistency.
Thanks for your feedback.
Offline
Hi Arnaud, that is not working for me.
My Server code is:
aServer.ServiceRegister(TServiceERefServer,[TypeInfo(IERefServerInterface)],sicShared).ContractExpected := CONTRACT_NAME;
My Server appears to be starting fine but when I call the following client method:
FClient.ServiceRegister([TypeInfo(IERefServerInterface)],sicShared,CONTRACT_NAME);
It goes into the following and fails by raising the exception at the bottom of the code segment:
constructor TServiceFactoryClient.Create(aRest: TSQLRest;
aInterface: PTypeInfo; aInstanceCreation: TServiceInstanceImplementation;
const aContractExpected: RawUTF8);
var i, siz: integer;
P: PCardinal;
Error, RemoteContract: RawUTF8;
begin
// extract RTTI from the interface
if not aRest.InheritsFrom(TSQLRestClientURI) then
EServiceException.CreateFmt('%s interface needs a Client connection',
[aInterface^.Name]);
inherited Create(aRest,aInterface,aInstanceCreation);
// check if this interface is supported on the server
if aContractExpected<>'' then
fContractExpected := aContractExpected; // override default contract
if not CallClient(SERVICE_PSEUDO_METHOD[imContract],@Error,'',@RemoteContract) then
raise EServiceException.CreateFmt('"%s" interface or %s routing not supported by server%s',
[fInterfaceURI,GetEnumNameTrimed(TypeInfo(TServiceRoutingMode),fRest.ServicesRouting),Error]);
The error message is:
'"ERefServerInterface" interface or REST routing not supported by server'
I suspect the problem is with the server because if I invoke the original call on the server:
aServer.ServiceRegister(TServiceERefServer,[TypeInfo(IERefServerInterface)],sicShared);
Then it correctly reports that the contracts are different when I make the client call passing my constant as the ExpectedContract.
Any ideas?
Paul
Offline
LOL - not sure why it happens but I have solved the problem.
I noticed that when it reported the error that the contracts were different, the hash code it said it was expecting had double quotes around it.
I changed the value of my ContractExpected constant to have double quotes around it - e.g. from 'synopse' to '"synopse"' and it works!
So there seems to be a 'feature' that the ContractExpected value must be enclosed with double quotes...
Offline
I can't take the latest version from Fossil - this goes live next week and there would be too much regression testing to change the underlying code at this stage! However our posts crossed - I have this working for me now.
If I ever make any money out of this project, how can I remunerate you for this very useful software you provide?
Offline
Hello there everyone!
I am having issue with fContractExpected. You're saying above that this variable can hold a version number.. and this variable is of type String.. so I was wondering if it could handle something else than just number i.e. letters or special caracters ?
So, I tried to give him a contract like 'ServiceProvider', but when I do, I get the following error : ''Invalid contract "" for TServiceParams: expected "ServiceProvider" '. What is odd is that the server's contract totally vanish in the maelstrom based on this message..
It is not specify in the documentation (Or I missed it.. ) whether it can only hold numeric caracters; that's why I am asking you this little question (:
Hope to read you promptly and thank you guys for this awesome work you're doing !!!
Offline
The contract vanished on the client side: check your client code.
In fact, the contract is just a string, so if you put some number converted to text, it will work.
Offline
Hello Arnaud!
Thanks for the quick answer !! (:
I should have precise that I am using TServiceClientAbstract class from SynCrossPlatformREST (V 1.18) as my Client is an Android one... I checked for the last release of your framework, and the variable has not vanished from SynCrossPlatform!
Were you talking about a none SynCross-Platform Client ?
Concerning the contents of the contract, it is only working when I put numbers .. and I wanted to put letters and special caracters.. but when I do, I get the error I wrote above..
For example, if I put "10.7" as a contract, the server side will interpret it as ''10,7" so I get the above error..
Thank you for your time
Last edited by M477h13u (2017-08-10 15:18:29)
Offline