Skip to main content

Calling ObjectScript Methods from .NET

This chapter describes methods of class IRIS that allow you to call ObjectScript class methods directly from your .NET application. See the following sections for details and examples:

Class Method Calls

The following methods of class IRIS call ObjectScript class methods, returning values of the type indicated by the method name: ClassMethodBool(), ClassMethodBytes(), ClassMethodDouble(), classMethodIRISList(), ClassMethodLong(), ClassMethodObject(), ClassMethodString(), and ClassMethodVoid(). You can also use ClassMethodStatusCode() to retrieve error messages from class methods that return ObjectScript %StatusOpens in a new tab (see “Catching %Status Error Codes”).

All of these methods take string arguments for className and methodName, plus 0 or more method arguments, which may be any of the following types: int?, short?, string, long?, double?, float?, byte[], bool?, DateTime?, IRISList?, or IRISObject. If the connection is bidirectional (see “Using .NET Inverse Proxy Objects”), then any .NET object can be used as an argument. See “Class IRIS Supported Datatypes” for more information about how the Native SDK handles these datatypes.

Trailing arguments may be omitted in argument lists, either by passing fewer than the full number of arguments, or by passing null for trailing arguments. An exception will be thrown if a non-null argument is passed to the right of a null argument.

Calling ObjectScript class methods

The code in this example calls class methods of each supported datatype from ObjectScript test class User.NativeTest (listed immediately after the example). Assume that variable iris is a previously defined instance of class IRIS and is currently connected to the server.

  String className = "User.NativeTest";
  String comment = "";
  try{
  comment = "cmBoolean() tests whether two numbers are equal (true=1,false=0): ";
  bool boolVal = iris.ClassMethodBool(className,"cmBoolean",7,7);
  Console.WriteLine(comment+boolVal);

  comment = "cmBytes creates byte array [72,105,33]. String value of array: ";
  byte[] byteVal = iris.ClassMethodBytes(className,"cmBytes",72,105,33);
  Console.WriteLine(comment+ (new String(byteVal)));

  comment = "cmString() concatenates \"Hello\" + arg: ";
  string stringVal = iris.ClassMethodString(className,"cmString","World");
  Console.WriteLine(comment+stringVal);

  comment = "cmLong() returns the sum of two numbers: ";
  Long longVal = iris.ClassMethodLong(className,"cmLong",7,8);
  Console.WriteLine(comment+longVal);

  comment = "cmDouble() multiplies a number by 1.5: ";
  Double doubleVal = iris.ClassMethodDouble(className,"cmDouble",10);
  Console.WriteLine(comment+doubleVal);

  comment = "cmProcedure assigns a value to global array ^cmGlobal: ";
  iris.ClassMethodVoid(className,"cmVoid",67);
  // Read global array ^cmGlobal and then delete it
  Console.WriteLine(comment+iris.GetInteger("^cmGlobal"));
  iris.Kill("cmGlobal");

  comment = "cmList() returns a $LIST containing two values: ";
  IRISList listVal = iris.ClassMethodList(className,"cmList","The answer is ",42);
  Console.WriteLine(comment+listVal.Get(1)+listVal.Get(2));
  } catch (Exception e){
    Console.WriteLine("method failed");
  }

ObjectScript Class User.NativeTest

To run the previous example, this ObjectScript class must be compiled and available on the server:

Class User.NativeTest Extends %Persistent
{
ClassMethod cmBoolean(cm1 As %Integer, cm2 As %Integer) As %Boolean
{
    Quit (cm1=cm2)
}
ClassMethod cmBytes(cm1 As %Integer, cm2 As %Integer, cm3 As %Integer) As %Binary
{
    Quit $CHAR(cm1,cm2,cm3)
}
ClassMethod cmString(cm1 As %String) As %String
{
    Quit "Hello "_cm1
}
ClassMethod cmLong(cm1 As %Integer, cm2 As %Integer) As %Integer
{
    Quit cm1+cm2
}
ClassMethod cmDouble(cm1 As %Double) As %Double
{
    Quit cm1 * 1.5
}
ClassMethod cmVoid(cm1 As %Integer)
{
    Set ^cmGlobal=cm1
    Quit ^cmGlobal
}
ClassMethod cmList(cm1 As %String, cm2 As %Integer)
{
    Set list = $LISTBUILD(cm1,cm2)
    Quit list
}
}

You can test these methods by calling them from the Terminal. For example:

USER>write ##class(User.NativeTest).cmString("World")
Hello World
Note:
Functions and Procedures

Earlier versions of the Native SDK provided methods that directly accessed ObjectScript functions and procedures. These methods have been removed due to security concerns. Functions and procedures can still be called indirectly by making them available as methods in an ObjectScript wrapper class.

Calling Class Library Methods

Most of the classes in the InterSystems Class Library use a calling convention where methods only return a %StatusOpens in a new tab value. The actual results are returned in arguments passed by reference. This section describes how to pass by reference and read %StatusOpens in a new tab values.

Using Pass-by-reference Arguments

The Native SDK supports pass by reference for methods. To pass an argument by reference, assign the argument value to an instance of class ADO.IRISReference and pass that instance as the argument:

  IRISReference valueRef = new IRISReference(""); // set initial value to null string
  iris.ClassMethodString("%SomeClass","SomeMethod",valueRef);
  String myString = valueRef.value;               // get the method result

Here is a working example:

Using pass-by-reference arguments

This example calls %SYS.DatabaseQuery.GetDatabaseFreeSpace()Opens in a new tab to get the amount of free space (in MB) available in the iristemp database.

  IRISReference freeMB = new IRISReference(0); // set initial value to 0
  String dir = "C:/InterSystems/IRIS/mgr/iristemp"; // directory to be tested
  Object status = null;

  try {
    Console.Write("\n\nCalling %SYS.DatabaseQuery.GetDatabaseFreeSpace()... ");
    status = iris.ClassMethodObject("%SYS.DatabaseQuery","GetDatabaseFreeSpace",dir,freeMB);
    Console.WriteLine("\nFree space in " + dir + " = " + freeMB.value + "MB");
  }
  catch (IRISException e) {
    Console.Write("Call to class method GetDatabaseFreeSpace() returned error:");
    Console.WriteLine(e.getMessage());
  }

prints:

Calling %SYS.DatabaseQuery.GetDatabaseFreeSpace()...
Free space in C:/InterSystems/IRIS/mgr/iristemp = 8.9MB

Catching %Status Error Codes

When a class method has ObjectScript %StatusOpens in a new tab as the return type, you can use ClassMethodStatusCode() to retrieve error messages. When a class method call fails, the resulting IRISException error will contain the %StatusOpens in a new tab error code and message.

In the following example, the ValidatePassword() method returns a %StatusOpens in a new tab object. If the password is invalid (for example, password is too short) an exception will be thrown and the %StatusOpens in a new tab message will explain why it failed. Assume that variable iris is a previously defined instance of class IRIS and is currently connected to the server.

Using ClassMethodStatusCode() to catch ObjectScript %Status values

This example passes an invalid password to %SYSTEM.Security.ValidatePassword()Opens in a new tab and catches the error message.

  String className = "%SYSTEM.Security";
  String methodName = "ValidatePassword";
  String pwd = ""; // an invalid password
  try {
// This call will throw an IRISException containing the %Status error message:
    iris.ClassMethodStatusCode(className,methodName,pwd);
// This call would fail silently or throw a generic error message:
    Object status = iris.ClassMethodObject(className,methodName,pwd);
    Console.WriteLine("\nPassword validated!");

  } catch (IRISException e) {
    Console.WriteLine("Call to "+methodName+"(\""+pwd+"\") returned error:");
    Console.WriteLine(e.getMessage());
  }

Notice that this example deliberately calls a method that does not use any pass by reference arguments.

To experiment with a more complex example, you can try catching the status code in the previous example (Using pass-by-reference arguments). Force an exception by passing an invalid directory.

Note:
Using IRISObject.InvokeStatusCode() when calling Instance methods

The ClassMethodStatusCode() method is used for class method calls. When you are invoking proxy object instance methods (see “Using .NET Inverse Proxy Objects”) the IRISObject.InvokeStatusCode() method can be used in exactly the same way.

FeedbackOpens in a new tab