Skip to main content

Sample Code

The standard Caché installation includes a sample project that demonstrates how to generate and use Caché proxy classes with .NET code. This chapter describes how to compile and run the project, and provides a convenient copy of the Caché source code.

Compiling and Running the .NET Test Project

The project code consists of two parts:

The following sections describe how to compile and run the project.

Compiling the .NET Assembly

Open the RemoteTest project file (RemoteTest.csproj) in Visual Studio and compile it. The DotNetGatewaySamples.dll file will be created in ..remote\test\obj\Debug. This is the assembly that will be imported into Caché.

Creating and Running the Server

  1. Create a .NET Gateway server description, as described in Defining a Gateway Server.

  2. Start the server, as described in Running a Gateway Server.

Generating Caché Proxy Classes

To import the sample .NET classes, start a Terminal session and use the following syntax to run the ExpressImport() method of the %Net.Remote.ImportHelperOpens in a new tab class:

  do ##class(%Net.Remote.ImportHelper).ExpressImport(gatewaySamplesDll,port)

where gatewaySamplesDll is a fully qualified path to DotNetGatewaySamples.dll (which you generated in step 1), and port is the port number of the Gateway server over which the proxy classes communicate with the .NET classes (which you started in step 3).

For example:

  do ##class(%Net.Remote.ImportHelper).ExpressImport(
    "C:\InterSystems\Cache\dev\dotnet\samples\remote\test\obj\Debug\DotNetGatewaySamples.dll",
    "55000")

You can open Atelier to examine the imported classes, which will be located in the remote/test package in the %SYS namespace.

This step should be repeated whenever you have modified or recompiled your .NET classes.

Running the Caché DotNet.Test Examples

The %Net.Remote.DotNet.TestOpens in a new tab class includes two test methods, Test() and TestArrays(). For both methods, the port argument is the number of the port over which the proxy classes communicate with the .NET classes (as described in the previous section), and the host argument identifies the machine on which the .NET Gateway server is running. The port argument is required; the host argument is optional and defaults to 127.0.0.1 (the local machine).

Test()

The Test() method shows how to use the sample classes delivered with Caché. Use the following syntax to run it at the Terminal:

  do ##class(%Net.Remote.DotNet.Test).Test(port,host)

See The Test() Method for a listing of the ObjectScript code.

TestArrays()

The TestArrays() method demonstrates the use of .NET arrays. Use the following syntax to run it at the Terminal:

  do ##class(%Net.Remote.DotNet.Test).TestArrays(port,host)

See The TestArrays() Method for a listing of the ObjectScript code.

Source Code for the Test Class

This section provides a convenient copy of the code found in the %Net.Remote.DotNet.TestOpens in a new tab class, which includes two test methods, Test() and TestArrays().

Class %Net.Remote.DotNet.Test Extends %RegisteredObject [ Abstract, ProcedureBlock ]
 {
    ClassMethod Test(port As %Integer, host As %String = "127.0.0.1") [ Final ]
    { ///...
    }
    ClassMethod TestArrays(port As %Integer, host As %String = "127.0.0.1") [ Final ]
    { ///...
    }
 }
Note:
Using the %objlasterror error status variable

The Test class includes references to %objlasterror, which should be used as a debug resource only (for example, in development code that does not yet report errors properly), so that the underlying problem can be diagnosed and the offending code's error reporting can be corrected. It is appropriate for such code to kill %objlasterror whenever it uses an error status that is an expected condition and not a reportable error.

Test() Method

The Test() method demonstrates how to interact with the DotNetGatewaySamples.dll assembly.

ClassMethod Test(port As %Integer, host As %String = "127.0.0.1") [ Final ] 
 { ///...
 }

For convenience, the code in this section has been divided into the following parts:

  • part 1 — connect to current namespace

  • part 2 — create and populate a Student object

  • part 3 — hashtable example

  • part 4 — modify the hashtable

  • part 5 — ArrayList and List examples

  • part 6 — create and populate an Address object

  • part 7 — change an Address

  • part 8 — get an array of Strings

  • part 9 — disconnect and catch errors

You can also examine this code by opening it in Atelier.

Test() method (part 1) — connect.
   Set %objlasterror="",$ZT="Error"
   // connect to current namespace, use 2 second timeout
   Set namespace=$Namespace,timeout=2
   Set classPath=##class(%ListOfDataTypes).%New()
   Set sampleDLL="dev/dotnet/bin/DotNetGatewaySamples.dll"
   Set samplePath=$SYSTEM.Util.InstallDirectory()_sampleDLL
   Do classPath.Insert(samplePath)

   // get a connection handle and connect
   Set gateway=##class(%Net.Remote.Gateway).%New()
   Set status=gateway.%Connect(host,port,namespace,timeout,classPath)
   If 'status Goto Error
Test() method (part 2) — create and populate a Student object.
   Set student=##class(remote.test.Student).%New(gateway,29,"976-01-6712")
   
   // get, set Date
   Write !,"setNextClass returned: "
   Write student.setNextClass($zd($h,3),$zt($h),"White Hall",3.0,0)
   Write !,"Next class on: ",$E(student.myGetNextClassDate(),1,10)
   Write $E(student.getNextClassTime(),11,*),!,!
   // set a String
   Do student.mySetName("John","Smith")
   // set an int

   Do student.mySetID(27)
   Write "Name: ",student.myGetName(),!
   Write "ID: ",student.myGetID(),!
   Write "SSN: ",student.getSSN(),!,!
   Write "Static method execute: "
   Write ##class(remote.test.Person).myStaticMethod(gateway),!,!
   Do ##class(remote.test.Person).setstaticProperty(gateway,89)
   Write "Static set/get: "
   Write ##class(remote.test.Person).getstaticProperty(gateway),!!
Test() method (part 3) — hashtable example
   Set grades=##class(System.Collections.Hashtable).%New(gateway)
   Do grades.Add("Biology",3.8)
   Do grades.Add("French",3.75)
   Do grades.Add("Spanish",2.75)
   Do student.mySetGrades(grades)
   Set grades=student.myGetGrades()

   Write "Student has completed the following "
   Write grades.getuCount()," classes:",!
   Set keys=grades.getuKeys().GetEnumerator()
   Set values=grades.getuValues().GetEnumerator()
   while (keys.MoveNext())
   {
      If (values.MoveNext()) 
         Write "  ",keys.getuCurrent()," ",values.getuCurrent(),!
   }
   Write !,"Highest grade: ",student.myGetHighestGrade()
Test() method (part 4) — modify the hashtable.
   Write !,"Now taking: Calculus, Chemistry, English Comp",!,!
   Do student.setGrade("Calculus",3.5)
   Do student.setGrade("Chemistry",3.92)
   Do student.setGrade("English Comp",2.5)
   Write "English Comp Grade: ",student.getGrade("English Comp"),!
   Set grades=student.myGetGrades()
   Write !,"Student has completed the following "
   Write grades.getuCount()," classes:",!
   Set keys=grades.getuKeys().GetEnumerator()
   Set values=grades.getuValues().GetEnumerator()
   while (keys.MoveNext())
   {
      If (values.MoveNext()) 
         Write "  ",keys.getuCurrent()," ",values.getuCurrent(),!
   }
   Write !,"Highest grade now: "
   Write student.myGetHighestGrade()

Test() method (part 5) — ArrayList and List examples.
   Set sports=##class(System.Collections.ArrayList).%New(gateway)
   // Example of using Type.GetType; to use it, replace the above line with the 
   // following two lines: (also make sure to import System.Activator)
   // Set arrayListClass=
   //    ##class(System.Type).GetType(gateway,"System.Collections.ArrayList")
   // Set sports=##class(System.Activator).CreateInstance(gateway,arrayListClass)
   Do sports.Add("Basketball")
   Do sports.Add("Tennis")
   Do sports.Add("Running")
   Do sports.Add("Swiming")
   Do student.mySetFavoriteSports(sports)

    // set/get a list of Strings
   Set list=student.myGetFavoriteSports()
   Write !,"Student's favorite sports are: ",!
   For i=0:1:list.getuCount()-1 {
      Write "  "_list.getuItem(i),!
   }

Test() method (part 6) — create and populate an Address object.
   // set an object
   Set home=##class(remote.test.Address).%New(gateway)
   Set street=##class(remote.test.Street).%New(gateway)
   Do street.setname("Memorial Drive")
   Do street.setnumber("One")
   Do home.mySetCity("San Diego")
   Do home.mySetStreet(street)
   Do home.mySetState("CA")
   Do home.mySetZip("20098")
   Do student.sethome(home)

   // get an object
   Write !,"Student's address: ",!
   Set home2=student.gethome()
   Write "  "_student.gethome().getstreet().getname(),!
   Write "  "_home2.myGetCity()_", "_home2.myGetState()_" "_home2.myGetZip(),!,!

Test() method (part 7) — change an Address.
   Write "Change address",!
   Set newHome=##class(remote.test.Address).%New(gateway)
   Set newStreet=##class(remote.test.Street).%New(gateway)
   Do newStreet.setnumber("456")
   Do newStreet.setname("Del Monte")
   Do newHome.mySetCity("Boston")
   Do newHome.mySetState("MA")
   Do newHome.mySetStreet(newStreet)
   Do newHome.mySetZip("40480")
   Set tempAddress=##class(remote.test.Address).%New(gateway)
   Do student.getAddressAsReference(.tempAddress)
   Write "City, before address change: "_tempAddress.myGetCity(),!
   Do student.changeAddress(home,newHome)
   Do student.getAddressAsReference(.tempAddress)
   Write "City, after address change: "_tempAddress.myGetCity(),!
Test() method (part 8) — get an array of Strings.
   Set list=student.getAddressAsCollection()
   Write !,"Student's new address is: ",!
   Write "  "_list.GetAt(4),!
   Write "  "_list.GetAt(1)_", "_list.GetAt(2)_" "_list.GetAt(3),!
   Write !,"Old addresses:",!
   Set oldAddresses=##class(%ListOfObjects).%New(gateway)
   Set newAdd=##class(remote.test.Address).%New(gateway)
   Set add2=student.getOldAddresses(home,.oldAddresses,.newAdd)
   For i=1:1:oldAddresses.Count() {
      Set oldAddress=oldAddresses.GetAt(i)
       Write !,"Address "_i_":",!
       Write oldAddress.getstreet().getnumber()
       Write " "_oldAddress.getstreet().getname(),!
       Write oldAddress.getcity()
       Write ", "_oldAddress.getstate()
       Write " "_oldAddress.getzip(),!
   }      
   Write !,"Most recent Address:",!
   Write add2.getstreet().getnumber()_" "_add2.getstreet().getname(),!
   Write add2.getcity()
   Write ", "_add2.getstate()
   Write " "_add2.getzip(),!
   Write !,"Least Recent Address: ",!
   Write newAdd.getstreet().getnumber()_" "_newAdd.getstreet().getname(),!
   Write newAdd.getcity()
   Write ", "_newAdd.getstate()
   Write " "_newAdd.getzip(),!
Test() method (part 9) — disconnect and catch errors.
   // Disconnect
   Do gateway.%Disconnect()
   Write !,"Test Successfully Completed"
   Quit
Error ; an error occurred
   Use 0
   If %objlasterror'="" 
      { Write $system.OBJ.DisplayError(%objlasterror) } 
   Else { Write $ze }

The TestArrays() Method

The TestArrays() method demonstrates the use of .NET arrays.

ClassMethod TestArrays(port As %Integer, host As %String = "127.0.0.1") [ Final ] 
 { ///...
 }

For convenience, the code in this section has been divided into the following parts:

  • part 1 — connect.

  • part 2 — create test Person object and test string arrays.

  • part 3 — create and populate Address objects.

  • part 4 — insert array of Address objects.

  • part 5 — use a binary stream.

  • part 6 — disconnect and catch errors.

You can also examine this code by opening it in Atelier.

TestArrays() method (part 1) — connect.
   Set %objlasterror="",$ZT="Error",namespace=$Namespace,timeout=2
   Set classPath=##class(%ListOfDataTypes).%New()
   Set sampleDLL="dev/dotnet/bin/DotNetGatewaySamples.dll"
   Set samplePath=$SYSTEM.Util.InstallDirectory()_sampleDLL
   Do classPath.Insert(samplePath)
   Set gateway=##class(%Net.Remote.Gateway).%New()
   Set status=gateway.%Connect(host,port,namespace,timeout,classPath)
   If 'status Goto Error
TestArrays() method (part 2) — create test Person object and test string arrays.
   Set test=##class(remote.test.Person).%New(gateway)
   
   // test simple string arrays
   Set stringArray=##class(%ListOfDataTypes).%New()
   Do stringArray.Insert("test string one")
   Do stringArray.Insert("test string two")
   Do stringArray.Insert("test string three")
   Do stringArray.Insert("test string four")

   // test simple string arrays
   Do test.setStringArray(stringArray)
   Set outStringArray=test.getStringArray()
   
   For i=1:1:outStringArray.Count() {
       Write "String "_i_" : "_outStringArray.GetAt(i),!
   }
TestArrays() method (part 3) — create and populate Address objects.
   // test array of objects
   Set home=##class(remote.test.Address).%New(gateway)
   Set street=##class(remote.test.Street).%New(gateway)
   Do street.setname("Memorial Drive")
   Do street.setnumber("One")
   Do home.mySetCity("Cambridge")
   Do home.mySetStreet(street)
   Do home.mySetState("MA")
   Do home.mySetZip("02142")

   Set home2=##class(remote.test.Address).%New(gateway)
   Set street2=##class(remote.test.Street).%New(gateway)
   Do street2.setname("Santa Cruz Ave")
   Do street2.setnumber("4555")
   Do home2.mySetCity("San Diego")
   Do home2.mySetStreet(street2)
   Do home2.mySetState("CA")
   Do home2.mySetZip("92109")
TestArrays() method (part 4) — insert array of Address objects.
   Set addressArray=##class(%ListOfObjects).%New()
   Do addressArray.Insert(home)
   Do addressArray.Insert(home2)

   Do test.setAddressArray(addressArray)
   Set addressArray=test.getAddressArray()
   For i=1:1:addressArray.Count() {
      Set home=addressArray.GetAt(i)
       Write !,"Address "_i_":",!
       Write home.getstreet().getnumber()_" "_home.getstreet().getname(),!
       Write home.getcity()
       Write ", "_home.getstate()
       Write " "_home.getzip(),!
   }
TestArrays() method (part 5) — use a binary stream.
   // byte[] is mapped as %GlobalBinaryStream
   Write !,"Byte array test:",!
   Set byteStream=##class(%GlobalBinaryStream).%New()
   Do byteStream.Write("Global binary stream")

   // Note that byteStream is passed in by value, so any changes on the DotNet
   // side will be ignored. The next example will pass the stream by reference
   // meaning changes on the DotNet side will be reflected here as well
   Do test.setByteArray(byteStream)
   
   Set result=test.getByteArray()
   Write result.Read(result.SizeGet()),!

   Set readStream=##class(%GlobalBinaryStream).%New()
   // we need to 'reserve' a number of bytes since we are passing the stream
   // by reference (DotNet's equivalent is byte[] ba = new byte[max];)
   For i=1:1:50 Do readStream.Write("0")
   
   Set bytesRead=test.read(.readStream,50)
   Write readStream.Read(bytesRead),!
TestArrays() method (part 6) — disconnect and catch errors.
   Do gateway.%Disconnect()
   Write !,"Test Successfully Completed"
   Quit
Error
   Use 0
   If %objlasterror'="" 
      { Write $system.OBJ.DisplayError(%objlasterror) } 
   Else { Write $ze }
 // end of method TestArrays()
FeedbackOpens in a new tab