Getting Started with CSharp Silverlight DataSnap Mobile Connector

From RAD Studio
Jump to: navigation, search

Go Up to Getting Started with DataSnap Mobile Connectors


This topic is a guide for generating and using the C# Silverlight DataSnap proxy, for use with Windows Phone 7 mobile development. The C# Silverlight proxy supports all the same data types that DataSnap itself supports. Special C# classes have been created to wrap those DBX and Delphi types, and their usage is similar to the usage in Delphi.

When requested, the DataSnap REST server generates and dispatches the proxy class used to invoke the methods on the server. This is very similar to the proxy generation you might already be familiar with, but also includes the process of zipping up the proxy and all dependencies, and sending this zip file to the requester.

For more information on this process, see Getting Started with DataSnap Mobile Connectors.

How to Download C# Silverlight Proxy Files from a DataSnap REST Server

First you need to obtain a copy of Win32ProxyDownloader.exe, available in the \bin directory of your product installation. This file and where to obtain a copy is further discussed in Getting Started with DataSnap Mobile Connectors.

The downloader is a simple utility that helps with asking the server for the proxy and other files needed for communication with the server.

To use the proxy downloader, you need to provide the following parameters:

  • -language (required): Specifies the mobile platform and language of the requested proxy. For Windows Phone 7, use csharp_silverlight.
  • -protocol: Specifies the connection protocol to use: either http or https. The default is http.
  • -host: Specifies the port and host name or IP address to connect to. Default is localhost with port 80. To specify a different name or port, fully qualify the name with the port number, separated by a colon (":")
  • -output: Specifies the folder to download the proxy files into. If not specified, the current folder is used.

The following is an example that uses most of the parameters mentioned above:

 C:\Win32ProxyDownloader.exe -language csharp_silverlight -host 127.0.0.1:8080 -output C:\test

After executing the downloader, the C# Silverlight proxy files are copied into the specified output folder. These files include the following:

  • JSON parsing dll
  • Static C# source files required by the proxy
  • DSProxy.cs, the generated proxy

The main file is DSProxy.cs, which declares the class that contains all the methods defined on the server.

How to use the DSProxy class

The code below shows the DSProxy.cs (C#) file generated by the server. It contains a TServerMethods1 class, which encapsulates the server methods. The server has only one method (EchoString), and the C# Class TServerMethods1 implements it appropriately. The proxy generator has automatically generated all the code for connecting to the server and executing the methods. See the C# code for the EchoString method below:

using System;
using System.Threading;

namespace Embarcadero.DataSnap.WindowsPhone7
{
  public class DSProxy
  {
    public class TServerMethods1 : DSAdmin
    {
      public TServerMethods1(DSRESTConnection Connection, ExceptionCallback ExCal) : base(Connection, ExCal)
      {
      }

      private DSRESTParameterMetaData[] TServerMethods1_EchoString_Metadata;
      private DSRESTParameterMetaData[] get_TServerMethods1_EchoString_Metadata() {
        if (TServerMethods1_EchoString_Metadata == null) {
          TServerMethods1_EchoString_Metadata = new DSRESTParameterMetaData[] {
              new DSRESTParameterMetaData("Value", DSRESTParamDirection.Input, 
                                                    DBXDataTypes.WideStringType, "string"),
              new DSRESTParameterMetaData("", DSRESTParamDirection.ReturnValue, 
                                              DBXDataTypes.WideStringType, "string"),
          };
        }
        return TServerMethods1_EchoString_Metadata;
      }

      /**
       * @param Value [in] - Type on server: string
       * @return result - Type on server: string
       */
      public delegate void EchoStringCallback(String Result);

      public void EchoString(String Value, EchoStringCallback callback = null, ExceptionCallback ExCal = null)
      {
        DSRESTCommand cmd = getConnection().CreateCommand();
        cmd.setRequestType(DSHTTPRequestType.GET);
        cmd.setText("TServerMethods1.EchoString");
        cmd.prepare(get_TServerMethods1_EchoString_Metadata());
        InternalConnectionDelegate EchoStringDel = () => {
          if (callback != null) {
            try {
              callback.DynamicInvoke(cmd.getParameter(1).getValue().GetAsString());
            } catch (Exception ex) {
              if (ExCal != null) 
                getConnection().syncContext.Send(new SendOrPostCallback(x => 
                   ExCal.DynamicInvoke(ex.InnerException)), null);
              else 
                getConnection().syncContext.Send(new SendOrPostCallback(x => 
                  BaseExCal.DynamicInvoke(ex.InnerException)), null);
            }
          }
        };
        cmd.getParameter(0).getValue().SetAsString(Value);
        getConnection().execute(cmd, this, EchoStringDel, ExCal);
      }
    }
  }
}

The first step in using the proxy class is to create and set up a connection to the server. Class DSRESTConnection encapsulates all the properties and methods needed for connecting to the server. Just create the connection and set up the properties as shown below:

DSRESTConnection connection = new DSRESTConnection();
connection.setHost("hostname");
connection.setPort(portnumber);
connection.setProtocol("http");
  • The host property specifies the host name or IP address.
  • The port property specifies the port on which the server is listening on.
  • The protocol property specifies the protocol to use for the connection. Specifically: either http or https.

To invoke the server methods remotely, just create the proxy class, passing the connection, and then call the method:

DSRESTConnection connection = new DSRESTConnection();
connection.setHost("localhost");
connection.setPort(8080);
connection.setProtocol("http");

DSProxy.TServerMethods1 Proxy = new DSProxy. TServerMethods1(connection, ExceptionCallback);

Proxy.EchoString("teststring", (String Result) =>
{
   // ...
}, ExceptionCallback);

public void ExceptionCallback(Exception e)
{
   // ...
}

Example of a Server Method with a var Parameter

The following example is the code that is generated when your server method contains a var parameter or returns multiple results. This is the Delphi code for the server method:

function TServerMethods1.VarParamTest(var Value: string): string;
begin
  Value := StrUtils.ReverseString(Value);
  Result := Value;
end;

And here is the generated proxy code to invoke that server method:

private DSRESTParameterMetaData[] TServerMethods1_VarParamTest_Metadata;
private DSRESTParameterMetaData[] get_TServerMethods1_VarParamTest_Metadata()
{
  if (TServerMethods1_VarParamTest_Metadata == null) {
    TServerMethods1_VarParamTest_Metadata = new DSRESTParameterMetaData[] {
      new DSRESTParameterMetaData("Value", DSRESTParamDirection.InputOutput, 
                                           DBXDataTypes.WideStringType, "string"),
      new DSRESTParameterMetaData("", DSRESTParamDirection.ReturnValue, 
                                     DBXDataTypes.WideStringType, "string"),
    };
  }
  return TServerMethods1_VarParamTest_Metadata;
}

/**
 * @param Value [in/out] - Type on server: string

Please note that the method returns an instance of VarParamTestReturns. This special class holds the information about var (in/out) parameters as well as the result. The following example shows how to invoke the method and read the resulting values:

Proxy. VarParamTest ("Hello, World!", 
  (DSProxy.TServerMethods1.VarParamTestReturns Result) => {
     Debug.WriteLine(Result.Value);
     Debug.WriteLine(Result.returnValue);
  }
);

Both the new value of the parameter passed in and the result value are held by the Result instance. The value for Result.Value is "!dlroW ,olleH", and Result.returnValue is "Hello, World!".

How to Use Heavyweight callbacks

Heavyweight callbacks provide a way for DataSnap Servers to send nearly instantaneous notifications to REST clients. A client can register a callback for a specific topic on the server of interest, then whenever that topic is updated, the client receives a notification. This is, of course, a very simplified description of what heavyweight callbacks accomplish, but should be sufficient for the purposes of this document.

The first step towards using callbacks in your application is to create a custom callback class that is inherited from the abstract DBXCallback class and override the abstract "Execute" method. Following is an example implementation of this class:

public class MyCallback : DBXCallback {
  public override TJSONValue Execute(TJSONArray params) {
    Debug.WriteLine(Params.ToString());
    return new TJSONTrue();
  }
}

The DSClientCallbackChannelManager class manages the client's callbacks. It provides methods for registering and unregistering the callbacks, and closing one or all of them.

The constructor for DSClientCallbackChannelManager accepts 3 parameters:

  1. DSRESTConnection, specifying the server connection information
  2. A String that contains the name of the server channel to register with
  3. A String that contains the manager's ID (unique to the server)
DSCallbackChannelManager mngr = 
    new DSCallbackChannelManager(Connection, "chname", DSCallbackChannelManager.getNewManagerID());

Following is an example of registering a callback and then broadcasting to the same channel where it is registered:


public void testCallbacks(){

       DSAdmin admin = new DSAdmin(Connection, ManageExceptionCallback);
   mngr = new DSCallbackChannelManager(Connection," chname",DSCallbackChannelManager.getNewManagerID());
   mngr.registerCallback("mycb01", new MyCallback(), () =>
   {
	admin.BroadcastToChannel("chname", new TJSONString("This is a broadcast"),(bool b) =>
        {
          mngr.closeClientChannel();
        });  

}

public void ManageExceptionCallback(Exception e)
{
   // ...
}

The first parameter to the 'registerCallback' method is an ID for the callback (an ID that is unique to the client channel). The second parameter is the actual callback instance to register, and the third is a delegate method to invoke when the registration completes.

The above code is registering a new instance of the MyCallback class on the server, which is listening on the chname channel. After this registration is successful, the client calls BroadcastToChannel, sending the string "This is a broadcast" to all callbacks (including itself) that are listening on the "chname" channel.'

The third parameter to the BroadcastToChannel call is a delegate that gets invoked when the call returns from the server, containing a boolean value that says whether the server successfully handled the broadcast request. The above code then, in this nested delegate declaration, closes the channel manager, so that no more broadcasts are received.

See Also