サンプル・コード
Caché の標準インストールには、.NET コードでの Caché プロキシ・クラスの生成方法および使用方法を示すサンプル・プロジェクトが含まれています。この章は、プロジェクトのコンパイル方法および実行方法を説明し、Caché ソース・コードの便利なコピーを提供します。
.NET テスト・プロジェクトのコンパイルおよび実行
このプロジェクト・コードは、以下の 2 つの部分から構成されています。
-
<Cache-root>\dev\dotnet\samples\remote\test\ にある RemoteTest .NET プロジェクト
-
Caché クラス・ライブラリの一部である %Net.Remote.DotNet.TestOpens in a new tab クラス
以下のセクションでは、プロジェクトのコンパイル方法および実行方法を説明します。
.NET アセンブリのコンパイル
Visual Studio で RemoteTest プロジェクト・ファイル (RemoteTest.csproj) を開き、コンパイルします。DotNetGatewaySamples.dll ファイルは、..remote\test\obj\Debug で作成されます。これは、Caché にインポートされるアセンブリです。
サーバの作成および実行
-
"ゲートウェイ・サーバの定義" の説明に従って、.NET ゲートウェイ・サーバの記述を作成します。
-
"ゲートウェイ・サーバの実行" の説明に従って、サーバを起動します。
Caché プロキシ・クラスの生成
サンプルの .NET クラスをインポートするには、ターミナル・セッションを開始し、以下の構文を使用して %Net.Remote.ImportHelperOpens in a new tab クラスの ExpressImport() メソッドを実行します。
do ##class(%Net.Remote.ImportHelper).ExpressImport(gatewaySamplesDll,port)
ここで、gatewaySamplesDll は、(手順 1 で生成した) DotNetGatewaySamples.dll への完全修飾パスで、port は、プロキシ・クラスと (手順 3 で起動した) .NET クラスの通信に使用するゲートウェイ・サーバのポート番号です。
以下はその例です。
do ##class(%Net.Remote.ImportHelper).ExpressImport(
"C:\InterSystems\Cache\dev\dotnet\samples\remote\test\obj\Debug\DotNetGatewaySamples.dll",
"55000")
Atelier を開いて、インポートされたクラスを調べることができます。インポートされたクラスは、%SYS ネームスペースの remote/test パッケージに配置されます。
この手順は、.NET クラスを変更またはリコンパイルするたびに繰り返す必要があります。
Caché DotNet.Test の例の実行
%Net.Remote.DotNet.TestOpens in a new tab クラスには、Test() と TestArrays() の 2 つのテスト・メソッドがあります。両方のメソッドで、port 引数は、(前のセクションで説明したように) プロキシ・クラスと .NET クラスの通信に使用するポート番号で、host 引数は、.NET ゲートウェイ・サーバが稼動しているマシンを識別します。port 引数は必須です。host 引数はオプションで、既定では "127.0.0.1" (ローカル・マシン) に設定されます。
Test() メソッドは、Caché に付属しているサンプル・クラスの使用法を示します。以下の構文を使用して、このメソッドをターミナルで実行します。
do ##class(%Net.Remote.DotNet.Test).Test(port,host)
ObjectScript コードの一覧については、"Test() メソッド" を参照してください。
TestArrays() メソッドは、.NET 配列の使用法を示します。以下の構文を使用して、このメソッドをターミナルで実行します。
do ##class(%Net.Remote.DotNet.Test).TestArrays(port,host)
ObjectScript コードの一覧については、"TestArrays() メソッド" を参照してください。
テスト・クラスのソース・コード
このセクションでは、%Net.Remote.DotNet.TestOpens in a new tab クラスにあるコードの便利なコピーを提供します。これには、Test() および TestArrays() の 2 つのテスト・メソッドが含まれます。
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 ]
{ ///...
}
}
Test クラスには、%objlasterror への参照が含まれています。%objlasterror は、(エラーを正しく報告しない開発コードなどでの) デバッグ・リソースとしてのみ使用してください。これにより、根本的な問題を診断し、問題のあるコードのエラー報告を修正できます。これは、このようなコードが、想定された状態でかつ報告できないエラーであるエラー・ステータスを使用するたびに、%objlasterror を削除するのに適しています。
Test() メソッド
Test() メソッドは、DotNetGatewaySamples.dll アセンブリと対話する方法を示します。
ClassMethod Test(port As %Integer, host As %String = "127.0.0.1") [ Final ]
{ ///...
}
便宜上、このセクションのコードは以下のパートに分けられています。
-
パート 1 — 現在のネームスペースへの接続
-
パート 2 — Student オブジェクトの作成および生成
-
パート 3 — Hashtable の例
-
パート 4 — Hashtable の変更
-
パート 5 — ArrayList および List の例
-
パート 6 — Address オブジェクトの作成および生成
-
パート 7 — アドレスの変更
-
パート 8 — 文字列の配列の取得
-
パート 9 — 切断およびエラーの検出
このコードは Atelier で開いて調べることもできます。
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
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),!!
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()
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()
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),!
}
// 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(),!,!
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(),!
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(),!
// 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 }
TestArrays() メソッド
TestArrays() メソッドは、.NET 配列の使用法を示します。
ClassMethod TestArrays(port As %Integer, host As %String = "127.0.0.1") [ Final ]
{ ///...
}
便宜上、このセクションのコードは以下のパートに分けられています。
-
パート 1 — 接続
-
パート 2 — テスト Person オブジェクトの作成および文字列の配列のテスト
-
パート 3 — Address オブジェクトの作成および生成
-
パート 4 — Address オブジェクトの配列の挿入
-
パート 5 — バイナリ・ストリームの使用
-
パート 6 — 切断およびエラーの検出
このコードは Atelier で開いて調べることもできます。
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
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),!
}
// 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")
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(),!
}
// 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),!
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()