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

See Also