Calling Remoting SDK Servers (JavaScript)
Getting started
First of all, let's make a server. The simplest one from the template.
In the Delphi IDE chose File->New->Other->Remoting SDK->VCL standalone
, or in Visual Studio, choose File->New Project->Remoting SDK Server
.
Press Advanced Project Options
button and uncheck Create Test Client
checkbox because we don't need it.
Hit Ctrl+F9
to let codegen generate required units (Delphi) or double-click the RODL file and close Service Builder again (.NET). Select the NewService_Impl
source file and provide a simple implementation for the two test methods, Sum
and GetServerTime
Finally, drop TROJavaScriptHttpDispatcher (Delphi) or JavaScriptHttpDispatcher (.NET) component onto the server form or data module, and connect its Server
property to your server channel component. Compile and run the server, it is now ready to serve JavaScript clients.
The JavaScript Interface File
Next, let's generate the Interface file that contains the proxy object and definitions for our service, in JavaScript.
To do this, open your service RODL again (Remoting SDK | Edit Service Library
in Delphi, or double-clicking the RODL file again, in Visual Studio) and generate NewLibrary_intf.js
file via the CodeGen
menu. Save the file to a /html
subfolder next to your server executable.
Your NewLibrary_intf.js
file should look something like this:
// Service: NewService
function NewService(__channel, __message, __service_name) {
RemObjects.SDK.ROService.call(this, __channel, __message, __service_name);
this.fServiceName = this.fServiceName || __service_name || "NewService";
};
NewService.prototype.Sum = function(
A,
B,
__success, __error) {
try {
var msg = this.fMessage.clone();
msg.initialize(this.fServiceName, "Sum");
msg.write("A", "Integer", A);
msg.write("B", "Integer", B);
msg.finalize();
this.fChannel.dispatch(msg, function (__message) {
var __result = __message.read("Result", "Integer");
__success(
__result
);
}, __error);
} catch (e) {
__error(msg, e);
}
}
NewService.prototype.GetServerTime = function(
__success, __error) {
try {
var msg = this.fMessage.clone();
msg.initialize(this.fServiceName, "GetServerTime");
msg.finalize();
this.fChannel.dispatch(msg, function (__message) {
var __result = __message.read("Result", "DateTime");
__success(
__result
);
}, __error);
} catch (e) {
__error(msg, e);
}
}
Some Theory
Remoting SDK for JavaScript uses asynchronous model to call service methods, so each proxy class method takes callback functions to process method execution results and calls them when results are ready.
in
parameters are passed to the proxy method; method result and out
parameters are passed to the Success
callback. If you are using Asynchronous calls in Remoting SDK for Cocoa (and you should be!), then this will already be familiar to you.
The Error
callback is called, instead of Success
when an error occurs, and it takes an exception (usually, but not always local) and a Message
as arguments. There is a RemObjects.UTIL.showError
global function that can be passed as default error callback, which simply prints out the error message and call stack.
The Client Side
Ok, let's move on to the real client implementation. Create a index.html
file in the same /html
subfolder as before. (Note that ./html
and index.html
are merely the default values of the JavaScriptHttpDispatcher's properties – you can change the folder name and the default file's name via properties; you can also embedd your files as resource and have the JavaScriptHttpDispatcher serve them via callback events, instead of relting on external files)
We are going to call both Sum
and GetServerTime
methods, so let's add some input fields for terms and results and some buttons to issue commands.
Your index.html
should end up something like this:
<html>
<head>
<script src="RemObjectsSDK.js"></script>
<script src="NewLibrary_intf.js"></script>
<script>
var Service = new NewService("http://" + window.location.host + "/BIN");
function get_servertime() {
Service.GetServerTime(
function(result) {
document.getElementById("serverTime").value = result;
},
function(msg, ex) {
if (ex)
alert(ex);
else
alert(msg.getErrorMessage());
}
);
}
function get_sum() {
Service.Sum(document.getElementById("a").value, document.getElementById("b").value,
function(result) {
document.getElementById("result").value = result;
},
RemObjects.UTIL.showError
);
}
</script>
</head>
<body>
<b>Sum:</b>
<br>
A <input type="text" id="a"><br>
B <input type="text" id="b"><br>
<input type="button" onclick="get_sum()" value="A + B =">
<input type="text" id="result">
<hr>
<b>GetServerTime:</b>
<br>
<input type="button" onclick="get_servertime()" value="Server time:">
<input type="text" id="serverTime"><br>
</body>
</html>
And that's it. With your server running, open your favourite web browser and point it to http://localhost:8099/js/. (/js
, once again, is the default value for where the JavaScriptHttpDispatcher will serve its content – you can change it to any name you like, as long as it doesn't conflict with your regular message dispatchers (ie /bin
, /json
or the like)).
Tips & Tricks
BinMessage is used in this tutorial because it is "most powerful" message type among RemObject SDK Messages. Unfortunately, it's unavailable for Internet Explorer users, because it doesn't support posting binary data. They should switch to JSONMessage. Please note that in order to use it following JSONMessage properties have to be set to true
at the server side: WrapResult
, SessionIdAsId
, SendExtendedException
, IncludeTypeName
.
Even more, in some versions/modes IE doesn't support JSON. Then third-party JSON implementation should be used. For example, this one - https://github.com/douglascrockford/JSON-js