Question
Jose Jaime · Sep 24

%Stream.GlobalCharacter property in .NET API binding

Hi, 

I'm trying to connect to IRIS with .NET 4.5 and I see is quite different from Cache Method.

I have a connection and I can invoke a Method but I can't get %Stream.GlobalCharacter value as Class property and I can't use it in a ByRef parameter. With Cache we had the Intersystems.Data.CacheTypes namespace to use this "special" types. 

Is there any documentation to use the %Stream.GlobalCharacter as class property and ByRef Param?

Thanks!

Product version: IRIS 2021.1
00
1 0 7 152
Log in or sign up to continue

Hi, thanks for the info!.

I've read the documentation but here is not the answer for my problem. First like is about the IRIS %Stream.GlobalCharacter side and the others are about Cache. The connection systems has changed from Caché version. I have a working solutions for caché but it is different in IRIS.

This is part of my IRIS Objectscript side:

Class D.DPasarela Extends %Library.RegisteredObject
{

Property Value As %Numeric;

Property Title As %String;

Property Message As %String;

Property STREAM As %Stream.GlobalCharacter;

Method PostMsg(SessionId As %String, Msg As %String, STREAMin As %Stream.GlobalCharacter, ByRef STREAMout As %Stream.GlobalCharacter)
{

/***********

As you can see I have a ClassMethod  with some params. One of these is a reference to a %Stream.GlobalCharacter and there is a param in the class with this type.

In .NET side:

/*****************/

IRISConnect.ConnectionString = "Server = " + ServerForm.aGlobalVars.data.CacheIP + "; "
                  + "Port = " + ServerForm.aGlobalVars.data.CachePort + "; " + "Namespace = " + ServerForm.aGlobalVars.data.NameSpace + "; "
                  + "Password = " + ServerForm.aGlobalVars.data.CachePass + "; " + "User ID = " + ServerForm.aGlobalVars.data.CacheUser + "; ";
               

IRISConnect.Open();
IRIS iris = IRIS.CreateIRIS(IRISConnect);

IRISObject pasarela = (IRISObject)iris.ClassMethodObject("D.DPasarela", "%New");

byte[] bytesS = null; // In real world this is a BASE64 encoded JSON

IRISReference cacheStreamOUT = new IRISReference(null); // IS NOT CORRECT
pasarela.InvokeVoid("PostMsg",aSession, aMsg, bytesS, cacheStreamOUT);
int aValue = Convert.ToInt32(pasarela.GetLong("Value")); // OK!
string aTitle = pasarela.GetString("Title"); // OK!
string aMessage = pasarela.GetString("Message"); // OK!

aJSON = pasarela.GetBytes("STREAM"); // ERROR

/*****************/

In Cache client for .NET there was some utilities to manage CharacterStreams but it is not available in IRIS client for .NET. Is there any solution for this?-

Thanks!

COS:

Class dc.DPasarela Extends %RegisteredObject
{

Property Value As %Numeric;

Property Title As %String;

Property Message As %String;

Property STREAM As %Stream.TmpCharacter;

Method PostMsg(
  SessionId As %String,
  Msg As %String,
  bytesS As %Binary,
  STREAMin As %Stream.TmpCharacter,
  Output STREAMout As %Stream.TmpCharacter)
{
  set ..Value = 5,
      ..Title SessionId,
      ..Message Msg_" "_bytesS
  
  do:$IsObject(STREAMin) ..STREAM.CopyFrom(STREAMin)
  
  set STREAMout=##class(%Stream.TmpCharacter).%New()
  do STREAMout.Write("bla-bla-bla")
}

}

C#:

IRISObject pasarela = (IRISObject)iris.ClassMethodObject("dc.DPasarela""%New");
 
byte[] bytesS = new byte[3]; // In real world this is a BASE64 encoded JSON
bytesS[0] = 233; // é
bytesS[1] = 234; // ê
bytesS[2] = 59; // ;
 
IRISReference refSTREAMout = new IRISReference(null);
 
IRISObject STREAMin = (IRISObject)iris.ClassMethodObject("%Stream.TmpCharacter""%New");
STREAMin.InvokeString("Write","blablabla");
 
pasarela.InvokeVoid("PostMsg""aSession""aMsg", bytesS, STREAMin, refSTREAMout);
 
int aValue = Convert.ToInt32(pasarela.GetLong("Value")); // 5
string aTitle = pasarela.GetString("Title"); // aSession
string aMessage = pasarela.GetString("Message"); // aMsg éê;
string aSTREAMout = ((IRISObject)refSTREAMout.value).InvokeString("Read"); // bla-bla-bla
string aSTREAM = ((IRISObject)pasarela.GetObject("STREAM")).InvokeString("Read"); // blablabla

Hi Vitaly, thanks for your help!.

This code is great but I have a problem with strings. It seems strings are limited to a specified length. I pass JSON encoded in BASE64+gzip in the stream info and sometimes json size is soooo long. In this case the result string is not complete and is malformed. In Caché version the solutions was like this:

InterSystems.Data.CacheTypes.CacheCharacterStream stream = pasarela.STREAM;                           
mtdSignature.Clear();
mtdSignature.SetReturnType(CacheConnect, typeof(InterSystems.Data.CacheTypes.CacheCharacterStream));

pasarela.GetProperty("STREAM", mtdSignature);
InterSystems.Data.CacheTypes.CacheCharacterStream stream = ((InterSystems.Data.CacheTypes.CacheCharacterStream)((InterSystems.Data.CacheTypes.CacheObjReturnValue)(mtdSignature.ReturnValue)).Value);

byte[] arrbyte = new byte[(int)stream.Length];
byte[] arrbyte = pasarela.GetBytes("STREAM");
stream.Read(arrbyte, 0, (int)stream.Length);
aJSON = System.Text.Encoding.Unicode.GetString(arrbyte);

With this code there is no problem about Stream length. Can I convert value to []bytes??

Thanks

COS:

Class dc.DPasarela Extends %RegisteredObject
{

Property STREAM As %Stream.TmpBinary;

Method PostMsg()
{
  s=$tr($j("",$$$MaxStringLength)," ",$c(0))

  i=1:1:5 ..STREAM.Write(s)
}

}

C#

IRISObject STREAM;
MemoryStream stream = new MemoryStream();
string len1, len2;
 
IRISObject pasarela = (IRISObject)iris.ClassMethodObject("dc.DPasarela""%New");
 
pasarela.InvokeVoid("PostMsg");
 
STREAM = (IRISObject) pasarela.Get("STREAM");
 
while (!Convert.ToBoolean(STREAM.GetBool("AtEnd")))
{
    stream.Write(STREAM.InvokeBytes("Read"3641144),03641144);
}
 
len1 = STREAM.GetString("Size"); // 18205720 (3641144*5)
len2 = stream.Length.ToString(); // 18205720 (3641144*5)
 
// =========== AGAIN ===========
 
STREAM.InvokeVoid("MoveToEnd");
 
pasarela.InvokeVoid("PostMsg");
 
stream.SetLength(0);
 
while (!Convert.ToBoolean(STREAM.GetBool("AtEnd")))
{
    stream.Write(STREAM.InvokeBytes("Read"3641144)03641144);
}
 
len1 = STREAM.GetString("Size"); // 36411440 (18205720*2)
len2 = stream.Length.ToString(); // 36411440 (18205720*2)
 
byte[] bytesS = stream.ToArray();

Thanks! It works!

Is not probably the fastest and elegant code but its perfect for me.

Thanks so much!