Question
Emanuel Lazar · Jul 5

IRIS - Native API  and .NET Provider  - Have a little Regression to Cache .net Provider ?

 Native API  , IRIS 2019 regression vs Cache .Net provider 

1. checking the native API, with .net provider, from IS docs, I realize,

that it is not possible to wrap objectSricpt Class with .NET (C# for example) pure Class with it's methods/properties

and make pure instance syntax of: new myNetClass - as wrapper of irisClass.

as I realize, you can run  .Net Class , only with .Invoke or iris.ClassMethodVoid("class.name","method")

such syntax, cannot execute event driven on proprety change, let say, with it's build in mechanizm in .Net

 

2. IRIS 2019.

this version is missing the class IRISObject  ? I have to upgrade to IRIS2021 ?

 

 

 

 

Product version: IRIS 2019.1
00
2 0 18 109
Log in or sign up to continue

1. like it this way; if you want "net" property access you have to generate proxy classes which wrap the mentioned methods...

2. InterSystems.Data.IRISClient.AD.IRISObject  is in Assembly InterSystems.Data.IRISClient, maybe dll not matching framework version? (umpf, sorry didn't read that you're on 2019... don't know about that)

can you advice with code example, step-by-step

how to generate the proxy class, and then how I use it in .Net environment

this is taken from testlibrary - where "Appliance.User" is a custom defined Object. 
Using IRIS and invoking ClassMethod %Library.Pesistent.%OpenId to receive a ObjectReference to the stored object with ID 1. 
Using that ObjectReference i'm able to invoke %ClassName on that object to get the ClassName of that object. 
With tryBlock i'm using same extensions to invoke same helper methods wich encapsulate more classMethods from %Persistent - but that follows exactly same pattern...


using (var conn = ConnectionFactory.CreateConnection() as IRISADOConnection)
{

    var iris = IRIS.CreateIRIS(conn);
    var obj = iris.ClassMethodObject("Appliance.User", "%OpenId", 1 );
    Assert.NotNull(obj);
    
    var iObj = obj as IRISObject;
    Assert.NotNull(iObj);
    Assert.True(iObj.Oref() == "3@Appliance.User");
    
    var clsName = iObj.InvokeString("%ClassName", true );
    try
    {
        var id = iObj.InvokeString("%Id");
        iris.LockId(clsName, id);
        iris.UnLockId(clsName, id);
        
        //iris.ValidateIndex(clsName);
        iris.PurgeIndex(clsName);
        iris.BuildIndex(clsName);
        
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
        throw;
    }

so mainly you have to work with Iris Class Documentation to find details of the Method Signatures.

If it's a classMethod you can invoke the matching IRIS Method directly, if it's a InstanceMethod you have to invoke %OpenId or %New() to have a Object Handle and invoke Methods on them. 

Invoking the Methods on Iris is straight forward and not complicated - (used to be a pain with Cache); 

Be aware that RefrenceParameters and Results with .Net Interface MAY NOT correspond to IRIS Documentation - actually i can't give you a reliable advice on that.

N.B. Some method just DO NOT WORK with .Net Interface - mainly this are all Methods which produce multiple lines of output if invoked by Iris Terminal (e.g. %ValidateIndices). If i have to invoke a method like that i just wrap them into a userdefined IRIS Helper-Class and invoke this helper class. (you even might declare your user method as SQL Method beeing able to invoke this method by sql)

I think , I have difficulty to understand your example:

iris Class : 

PCG.myClass

with property:

myProperty

set objMyClass = ##class(PCG.myClass).%New()

set objMyClass.myProperty = "string Property"

in .Net :

1. I need to wrap the : PCG.myClass

2. make an instance of the myClass

3. set to .myProperty as String value, I expect syntax :

objNetMyClass.myProprty = "String Text in .Net Project"

just implemented  a small testClass to show what i mean:

public class TestClass : IDisposable
{

    public TestClass(IRISADOConnection conn, int idValue)
    {
        iris = IRIS.CreateIRIS(conn);
        proxy = (IRISObject)iris.ClassMethodObject("User.MyClass", "%OpenId", idValue);
        Id = idValue;
    }

    public TestClass(IRISADOConnection conn)
    {
        iris = IRIS.CreateIRIS(conn);
        proxy = (IRISObject)iris.ClassMethodObject("User.MyClass", "%New");
    }

    public void Save()
    {
        int related = 1;
        proxy.InvokeIRISStatusCode("%Save", related);
        if (!Id.HasValue)
        {
            Id = (int)proxy.InvokeLong("%Id");
        }
    }
    
    public string MyProperty
    {
        set
        {
            proxy.Set(nameof(MyProperty), value);
        }
        get
        {
            return proxy.GetString(nameof(MyProperty));
        }
    }

    internal int? Id;
    
    IRISObject proxy;
    IRIS iris;

    public void Dispose()
    {
        iris.Close();
    }
    
}

and testmethod to get an impression what's going on:

[Test]
public void pcg()
{

    using (var conn = ConnectionFactory.CreateConnection() as IRISADOConnection)
    {
        
        conn.ChangeNs("\"USER\"");
        var tc = new TestClass(conn);
        tc.MyProperty = "FuzziGagga";
        tc.Save();
        Assert.NotNull(tc.Id);
        var id = tc.Id.Value;

        tc = new TestClass(conn, id);
        var myProp = tc.MyProperty;
        Assert.True(myProp == "FuzziGagga");

    }
    
}

Hi Stefan,

1. this example looks, much better. and I understand your example.

you actually wrap property values set/get with Iris native commands get/set

2. now I want to add to this : .myProperty event handler,

so if .myProperty changed (in objectscript) I want to add in .Net notify listener

to fire  event with .Net syntax ,

how can I do it ?

i'm not sure if i understood rigth - your'e talking about a event listener on a database field change? (keep in mind, that the properties content is a database field which potentially could be changed by cos, sql or even direct global access)?

now I ask, only on .myProperty (in class) string change

can I "listen" to specific ^Global change or Node change ?

yes, that sounds for me like tracing to the database writer - i'm not aware of this functionality in any database at all. 

keep in mind that changing a database field depends on several factors - if you're in a transaction  it might look for the client who's running the update like the field is changed, for others not; If transaction fails the field content will be rolled back.

the "normal" way is just to poll the property regularly to see if it's been changed

I ask, only on .myProperty (in class) string change

I can trigger this event , with .Net Notify ?

how is the code syntax for that ?

I have done it On older Cache .net provider

i'm not sure if understood correctly, but for .net this normally is done like that:

public class TestClass : INotifyPropertyChanged
{
    
    public event PropertyChangedEventHandler PropertyChanged;

    public string Test
    {
        set
        {
            if (_test != value)
            {
                _test = value;
                PropertyChanged?.Invoke(this, nameof(Test));
            }
                
        }
        get
        {
            return _test;
        }
    }
    string _test;

}

Hi Stefan,

1.

yes , it's much closer, I'll check if it's actually fires the event.

2. each property\method definition in class I'll have to make the  wrap on iris get/set (no connection to event)?

3. get method arguments byRef from the irisClass ?

did not see any doc about, can it be done ?

the first two might be a bit off topic - this points more or less to .net architectural decisions. if you want email  me  directly (s-rieger@gmx.net) and i try to give you some hints.

3.: Did not look into that deep - do you have an example on which method you really need that?