Skip to main content

Using Dynamic Object Gateways

This chapter describes how to implement Object Gateways using dynamic proxy objects. In previous releases, static proxies had to be generated separately, compiled, and stored in the class library just like any other class (see Importing Java Classes in the previous chapter). Dynamic proxy objects do not require a separate import process before the business operation can start. The business operation simply creates and uses them as needed during runtime.

Introducing Dynamic Gateways

All versions of the Object Gateway can instantiate an external .NET object and manipulate it as if it were a native InterSystems IRIS object. This is accomplished by creating a proxy object that provides all of the same methods and properties as the corresponding .NET object. Any call on the proxy object triggers the corresponding method or property of the .NET object. There are currently two kinds of proxy objects:

  • Static proxies are standard ObjectScript classes, which must be individually generated and compiled before they can be used. If a new version of the .NET class changes the interface in any way, the corresponding proxy class must be regenerated and recompiled to match it.

  • Dynamic proxies are created at runtime by introspecting the current version of the .NET class. All dynamic proxies are instances of %Net.Remote.Object. Although each Object instance appears to have the same methods and properties as the corresponding .NET object, it actually uses an internal map of the interface to simulate these features.

In use, static and dynamic proxies are identical except for the way they are instantiated. For example:

// Static proxy: just call %New() on a pregenerated class
  set newFruit = ##class(Fruit).%New()

// Dynamic proxy: create an Object instance and specify the class to introspect
  set newFruit = ##class(%Net.Remote.Object).%New(gateway,"Fruit")

Creating and Using a Dynamic Object Gateway

This section describes the complete procedure for creating and running an Object Gateway that uses dynamic proxies:

Start the Object Gateway server

Since dynamic proxies are created at runtime, you need access to a server that can introspect .NET classes and return the information needed to generate the proxies.

To start the gateway, open the Management Portal and go to the Object Gateways Page, System Administration > Configuration > Connectivity > Object Gateways. This page displays all ObjectGateway descriptions that have been persisted to the database, and provides a convenient way to control, monitor, and modify the servers they describe. The following example displays information on the NetGate server, and indicates that an instance of that server is currently running:

The examples in this chapter will assume that the server named NetGate has been defined (see “Creating the NetGate Server Definition” for details).

Get the server definition and make sure the server is running

The Service class provides methods to start, stop, and test the server. Most of these methods require the server definition contained in an ObjectGateway object. In the following example, Service.OpenGateway() returns an ObjectGateway instance defining the server named NetGate. Service.IsGatewayRunning() uses the information to test the current state of the server, and Service.StartGateway() can start it if necessary.

try {
// Get a ObjectGateway instance that defines the NetGate server
  set st = ##class(%Net.Remote.Service).OpenGateway("NetGate",.OG)
  write !, "Using "_OG.Name_" server definition"

// Test to make sure the server is running. If not, start it
  if ('##class(%Net.Remote.Service).IsGatewayRunning(OG.Server,OG.Port,,.status)) {
    // Instantiate the server on the host machine
    set status = ##class(%Net.Remote.Service).StartGateway(OG.Name)
catch ex {
  write !,$system.OBJ.DisplayError(ex.AsStatus())
Exception Handling

Your ObjectScript code should always use try/catch for Object Gateway error handling. When the class running on the host machine encounters an exception, the dynamic proxy will throw %Net.Remote.Exception. In addition to standard status details, the Exception object contains call stack information, which is returned by calling method Exception.StackAsArray(.array). The information may be different between Java and .NET.

Define the location of your .NET classes and create a Gateway connection

Each dynamic proxy will access the corresponding .NET object through a Gateway object connected to the server. The Gateway object needs a path to each DLL containing a class you want to use. In this example, the location of the DLL containing class Fruit is specified in the last argument to Gateway.%Connect().

// define the location of the file containing the Fruit class
set fruitPath = ##class(%ListOfDataTypes).%New()
do fruitPath.Insert("C:\Dev\Fruit.dll")

// Connect a Gateway instance to server NetGate on the host machine
set GW = ##class(%Net.Remote.Gateway).%New()
set st = GW.%Connect(OG.Server, OG.Port, "USER",,fruitPath)

This example only adds one path, but you can insert a separate path for each DLL you want to use.

Create a dynamic proxy for .NET class Fruit and call some methods

In this example, an new instance of Object is created, specifying Fruit as the .NET class to introspect. The resulting dynamic proxy will communicate with the .NET object through Gateway instance GW (created in the previous example). Once the dynamic proxy is instantiated, it works just like a static proxy.

// Use GW connection to create a proxy for the Fruit class
set proxyFruit = ##class(%Net.Remote.Object).%New(GW,"Fruit")

write !,
write !,"Current fruit preference: ",!,"   "_proxyFruit.getFruit()
do proxyFruit.setFruit("Jujube")
write !,"Fruit preference has been reset: ",!,"   "_proxyFruit.getFruit()


This .NET class displays your favorite fruit.
Current fruit preference: UglyFruit
Fruit preference has been reset: Jujube
Disconnect and shut down the server

The connection remains open and the server continues to run until you explicitly disconnect and shut down. In this example, the Gateway.%Disconnect() method breaks the connection, but the server won’t release the port it uses until the call to Service.StopGatewayObject() stops it.

// Disconnect from the server
  set st = GW.%Disconnect()

// Stop the server
  set st =  ##class(%Net.Remote.Service).StopGatewayObject(OG)

Array Access

When a property is declared as an array, it is projected to the proxy as an instance of %Net.Remote.Object. To create a new array, call the Object.%New() method and use array class name syntax in place of the regular class name. Arguments are used as the initial values for the array. Here are some examples:

Array initialization

Array can be initialized by rank or elements:

// by rank
  set newArray = ##class(%Net.Remote.Object).%New(gateway,"String[2]")

// by elements
  set newArray = ##class(%Net.Remote.Object).%New(gateway,"String[]","A","B","C")

When rank and elements are both specified, rank must match element count.

// both rank and elements specified
  set newArray = ##class(%Net.Remote.Object).%New(gateway,"int[3]",11,22,33)

.NET multidimensional arrays are supported. They can only be initialized by rank:

// Create a two dimensional array by rank
  set newArray = ##class(%Net.Remote.Object).%New(gateway,"String[2,3]")
Getting and setting array elements

Besides supporting all the normal properties and methods available on an array object, Dynamic Gateway supports two special methods for accessing array elements:

  • %get(index)object.%get(index)is translated to object[index]

  • %set(index,value)object.%set(index,value) is translated to object[index] = value.

For example:

// Create a two dimensional array and populate it
  set arr = ##class(%Net.Remote.Object).%New(gateway,"String[2,3]")
  for x=0:1:1 {for y=0:1:2 {set i=x*3+y  do arr.%set(x,y,$CHAR(65+i)) }}

  write !,"Array length is" _arr.Length_" and rank is "_arr.Rank
  for x=0:1:1 {for y=0:1:2 {write "("_x_","_y_")="_arr.%get(x,y)_"  " }}


Array length is 6 and rank is 2
(0,0)=A  (0,1)=B  (0,2)=C  (1,0)=D  (1,1)=E  (1,2)=F

Gateway Reentrancy

Reentrancy means that when InterSystems IRIS code sends a request to .NET, the .NET code can respond with a request of its own using the same physical connection and context as the original request. The following is a typical call sequence:

  • Starting from the InterSystems IRIS side, a connection is made to .NET using a %Net.Remote.Gateway object, allowing us to create proxy objects that can make calls to .NET methods.

  • From a proxy, the .NET ADO.Gateway.GatewayContext.getIRIS() method can be called to create an instance of ADO.IRIS. The IRIS object uses the same connection and context as the proxy, and provides access to all the methods for invoking Native API calls (see “Using the InterSystems Native API for .NET”).

  • The IRIS object can call back into InterSystems IRIS, where it can get and set global values or call classmethods and functions. Making one of these calls puts us back in InterSystems IRIS code again.

  • From here, we can make another inner call back to .NET using the same Gateway connection. Method ##class(%Net.Remote.Gateway).%GetContextGateway() returns the Gateway object for the current context.

  • Calls back and forth between InterSystems IRIS and .NET can go on indefinitely, always using the same connection and context.

Getting an .ADO.IRIS object from GatewayContext()

The following example gets an ADO.IRIS object in .NET, and uses it to read a global value from the InterSystems database:

IRIS native = GatewayContext.getIRIS();
// Read the value of global ^GlobalName("value2")
if ( native != null ) {
  String globalVal = native.GetString("GlobalName","value2");

If the code is not invoked inside a valid Gateway context, the getIRIS() method will return a null object.

Getting a Gateway context object from within Native API calls

This example gets a %Net.Remote.Gateway object for the current context, and uses it to create a proxy for a .NET object in the same context:

set gateway = ##class(%Net.Remote.Gateway).%GetContextGateway()
if gateway'=$$$NULLOREF {
  set objFruit = ##class(%Net.Remote.Object).%New(gateway,"Fruit")

If the context is not valid, the Gateway object will be $$$NULLOREF.


In general, reentrancy support is not compatible with prior versions of the Object Gateway .

Example Classes

This section provides detailed descriptions of the two sample classes used in this chapter:

The .NET Fruit Class

This section lists the Fruit class used by most of the examples in this chapter. This trivial .NET class has all the features needed to demonstrate a simple proxy object: static class method id(), and property accessors getFruit() and setFruit().

The Fruit class
using System;
namespace demo {
  public class Fruit {
    public static String id() {
      return "This .NET class displays your favorite fruit.";
    public String fruit;
    public Fruit () {
      fruit = "Uglyfruit";
    public void setFruit(String newFruit) {
      fruit = newFruit;
    public String getFruit() {
      return "My favorite fruit is "+fruit;
    public static void main(String []args) {
      System.out.println("\nGenerating output from .NET class Fruit: ");
      Fruit myFruit = new Fruit ();

Creating the NetGate Server Definition

This section demonstrates how to create the NetGate Object Gateway server definition used by most of the examples in this chapter.

The Management Portal provides convenient interactive tools for creating and controlling Object Gateway servers (as mentioned earlier in this chapter), but this example will demonstrate what those tools are actually doing in the background. You can create and run a server with a few lines of ObjectScript code, specifying exactly the same information you would enter in the Management Portal.

The properties of an Object Gateway server are defined in an instance of %Net.Remote.ObjectGateway. The following code specifies properties for a .NET-based server named NetGate, persists the server definition in the InterSystems IRIS database, and then starts an instance of the server on the host machine.

Define server properties in an instance of ObjectGateway

This server will run on the same machine as InterSystems IRIS (since the Server property specifies localhost as the host machine), but this is not a requirement. The host machine only needs a copy of the server executable.

  set OG =  ##class(%Net.Remote.ObjectGateway).%New()

// Properties used in all server definitions
  set OG.Type = "2"   // Defines a .NET server
  set OG.Name  = "NetGate"
  set OG.Server  = ""
  set OG.Port  = "55602" // port number must be unique

// .NET-only properties
  set OG.AllowedIPAddresses = """
  set OG.FilePath  = "C:\InterSystems\IRIS\dev\dotnet\bin\v4.5\"
  // keep Exec64 default value
  set OG.DotNetVersion = "4.5"

The Object Gateway needs the FilePath and DotNetVersion paths to execute the command that will instantiate the server on the host machine. They are optional in this example (where localhost is the host machine), since they just specify the default paths to a version of the InterSystems.Data.Gateway64.exe executable (installed with InterSystems IRIS) and the corresponding version of .NET.

Save the server definition and run the server

Calling ObjectGateway.%Save() adds this definition to the list stored in the InterSystems IRIS database. When the server definition is persisted in the database, it will be listed on the Object Gateway Page in the Management Portal.

  write "Saving "_OG.Name
  set status = OG.%Save()

The definition can now be used to construct and run the command that will start an instance of the server on the host machine. You can start the server either by clicking Start on the Object Gateway Page, or by calling the %Net.Remote.Service.StartGateway() method as demonstrated below.

// Instantiate the server on the host machine
   set status = ##class(%Net.Remote.Service).StartGateway(OG.Name)