Yes, we have a .Net Gateway configured, and we have imported the .Net dll through the Studio wizard.

We have activated gateway log, but it doesn't say anything.

From an Ensemble Bussiness Operation we call the .Net method. The code is this:

Class bo.GenerarWord Extends EnsLib.DotNetGateway.AbstractOperation
{

Parameter INVOCATION = "Queue";

Method generarDocumento(pRequest As msg.WordRequest, Output pResponse As msg.WordResponse) As %Status
{
        #dim sc as %status
        #dim gateway as %Net.Remote.Gateway
        
        set pResponse = ##class(msg.WordResponse).%New()
        
        set sc = ..GetConnection(.gateway)
        
        if $$$ISERR(sc){
            set pResponse.mensaje = "Error ("_sc_"):"_$System.Status.GetErrorText(sc)
            
        }else{
            #dim ce as cysnet.MiClase.entity.ControlError
            #dim we as cysnet.MiClase.entity.WordEntity
            #dim plantilla as %String
            #dim documento as %String
            
            set ce = ##class(cysnet.MiClase.entity.ControlError).%New(gateway)
            set we = ##class(cysnet.MiClase.entity.WordEntity).%New(gateway)
            
            set plantilla = "C:\InterSystems\Ensemble\mgr\DLLWORDENS2\dlls\PlantillaTuneada.doc"
            set documento = "C:\InterSystems\Ensemble\mgr\DLLWORDENS2\dlls\"
            
            //set we.setuTitulo = "TITULO_ENS"
            
            do dao.EscribirWord(ce,plantilla,documento,we,"PRUEBA_ENS")
            
            $$$LOGINFO(ce.getuDebbug())
        }
        
        set pResponse.mensaje = "OK"
        Quit $$$OK
}

XData MessageMap
{
<MapItems>
        <MapItem MessageType="msg.WordRequest"> 
            <Method>generarDocumento</Method>
        </MapItem>
</MapItems>
}

The .Net code is this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using cysnet.MiClase.entity;
using System.IO;
using Microsoft.Office.Interop.Word;
 
namespace cysnet.MiClase
{
    public class MiClase
    {
        public String EscribirWord(ControlError ce, String fullPathPlantilla, String pathDocumento, WordEntity we, String numDocumento)
        {
 
            if (ce == null)
            {
                ce = new ControlError();
            }
            ce.Reset();
            ce.Debbug = fullPathPlantilla + " || " + pathDocumento + " || " + numDocumento + "  || ";
            ce.Debbug += " Iniciando método";
            String resultado = "";
            Application MSWord = new Application();
            Document documento;
 
            try
            {
                object oMissing = System.Reflection.Missing.Value;
                
                ce.Debbug += "RUTA DEL NUEVO DOCUMENTO:"+ pathDocumento + numDocumento +".docx";
 
                documento = MSWord.Documents.Add(ref oMissing, ref oMissing, ref oMissing, ref oMissing);
 
                ce.Debbug += " Abriendo plantilla Word";
                //Abrir Palntilla
 
                documento = MSWord.Documents.Open(fullPathPlantilla);
 
                ce.Debbug += " Escribiendo en marcadores";
                
                //Editar marcadores
                documento.Bookmarks["Titulo"].Range.Text = we.Titulo;
 
                ce.Debbug += " Guardando documento Word";
                //Guardar copia de la plantilla como documento
                documento.SaveAs(pathDocumento+numDocumento+".dot");
                
                ce.Debbug += " Cerrando documento Word";
                //Cerrar documento
                documento.Close();
                
                ce.Debbug += " Operación realizada con éxito";
            }
            catch (Exception e)
            {
                ce.MessageError = e.Message;
                ce.IsError = true;
            }
            finally
            {
                ce.Debbug += " Cerrando aplicación MsWord";
                //Cerrar la aplicación
                MSWord.Quit();
            }
 
            return resultado;
        }
    }
}

I have cleaned it a bit to be more legible. It has comments in spanish. I hope it doesn't matter.

Thank you for the information. We know about Ensemble Alerts, and we use it to alert on error, but we did not know that we can set it to alert on other things. The course has been very useful too.

We are using 2016.2.1 (Build 803U).

This is the way we generate JSON:

TEST>set x = ##class(test.msg.struct.TestXML).%New()
 TEST>set x.statusId = "111"
 TEST>set x.service = "222"
 TEST>do ##class(Ens.Util.JSON).ObjectToJSONStream(x, .obj1, "aelotu")
 TEST>w obj1.Read()
{       "statusId":"111",       "service":"222"}
 

And this is the definition of the object:

Class test.msg.struct.TestXML Extends (%SerialObject,%XML.Adaptor)
{
Property statusId As %String(MAXLEN = "", XMLNAME = "status_id");
Property service As %String(MAXLEN = "");
}

I had already thought about it, but we have a lot of properties with underscore, we would have to change everyone manually.

We can do that, but I don't like it.

Maybe changing something in the method ##class(%ZEN.Auxiliary.jsonProvider).%WriteJSONStreamFromObject() that if "XMLNAME" is defined, use that name instead property real name? But I don't know where to do that...

Thank you very much! I have tested this, and it's easier to create the full structure with this. This is very useful to us

Thanks to all of you.

I have extended the original class and tunned the method %ObjectToJSON like this:

ClassMethod %ObjectToJSON(pObject As %RegisteredObject, ByRef pVisited, pLevel As %Integer = 0, pFormat As %String = "aceloqtw") As %Status
{
    Set tSC = $$$OK
    Try {
        If ((pObject="")||'$IsObject(pObject)||($D(pVisited(pObject)))) {
            // cycle
            Write:pFormat["a"||'pLevel "null"
            Quit
        }
        Set pVisited(pObject) = ""
        Set tClass = $classname(pObject)
        If (tClass = "%ZEN.proxyObject") {
            Set tSC = pObject.%ToJSON(pLevel,pFormat)
            Quit
        }
        Set tLF=$S(pFormat["w":$C(13,10), pFormat["n":$C(10), 1:"")
        If pFormat'=$TR(pFormat,"it123456789") { Set tN=+$ZStrip(pFormat,"<E'N"), $P(tTab,$S(pFormat["t":$C(9),1:" "),1+$S(tN:tN,pFormat["t":1,1:4))="" }
        Else { Set tTab="" }
        Set tIncludeWhitespace = (tLF_tTab'="")
        If (pObject.%Extends("%Collection.AbstractList")) {
            Set tList = pObject
            Set tCount = tList.Count()
            If (pFormat["l" || tCount) {
                Write "["
                For n = 1:1:tCount {
                    Set tValue = tList.GetAt(n)
                    Write:n>1 ","
                    If $IsObject(tValue) {
                        If (tValue.%IsA("%ZEN.proxyObject")) {
                            Set tSC = tValue.%ToJSON(pLevel+1,pFormat)
                            Quit:$$$ISERR(tSC)
                        } Else {
                            Set tSC = ..%ObjectToJSON(tValue,.pVisited, pLevel+1, pFormat)
                            Quit:$$$ISERR(tSC)
                        }
                    } Else {
                        Write $$$ZENJSONVALUE(tValue,pFormat)
                    }
                }
                Quit:$$$ISERR(tSC)
                If tIncludeWhitespace Set tIndent="", $P(tIndent,tTab,pLevel+1)="" Write tLF_tIndent
                Write "]"
            }
            Quit
        }
        ElseIf (pObject.%Extends("%Stream.Object")) {
            Write """"
            #; Initialize stream read length, if needed
            If '$data(tStreamMaxReadLen) Set tStreamMaxReadLen = ($$$MaxLocalLength\2)
            Do pObject.Rewind()
            While 'pObject.AtEnd {
                Write $$$ZENJSONESCAPE(pObject.Read(tStreamMaxReadLen),pFormat)
            }
            Write """"
            Quit
        }
        If pFormat["o" || 'pLevel {
            Set tPropCount = ""
            If (tIncludeWhitespace && pLevel) Set tIndent="", $P(tIndent,tTab,pLevel+1)="" Write $S(pFormat["b":tLF_tIndent,1:" ")
            Write "{"
        } Else {
            Set tPropCount = 0
        }
        If pFormat["c" {
            // add class name to model
            Do nextProp
            Write $$$ZENJSONPAIR("_class",tClass,pFormat)
            // add id for persistent objects
            If (pObject.%IsA("%Library.Persistent")) {
                Do nextProp
                Set tID = pObject.%Id()
                Write $$$ZENJSONPAIR("_id",tID,pFormat)
            }
        }
        #; Special treatment for top-level array: output no matter what
        If pObject.%Extends("%Collection.AbstractArray") {
            #; write out (eligible) array elements/properties
            If pObject.%Extends("%Collection.AbstractArrayOfObj") {
                #; object elements
                Set tKey=""  For { Set tValue = pObject.GetNext(.tKey)  Quit:""=tKey
                    If $IsObject(tValue) {
                        If tValue.%Extends("%Stream.Object")||tValue.%Extends("%IO.I.Stream") {
                            Do tValue.Rewind()
                            If (pFormat["e" || tValue.Size()) {
                                Do nextProp
                                Write $$$ZENJSONPROP(tKey,pFormat)_":"""
                                #; Initialize stream read length, if needed
                                If '$data(tStreamMaxReadLen) Set tStreamMaxReadLen = ($$$MaxLocalLength\2)
                                #; Rewind non-%IO streams if needed
                                If tValue.AtEnd && tValue.%Extends("%Stream.Object") Do tValue.Rewind()
                                While 'tValue.AtEnd {
                                    Write $$$ZENJSONESCAPE(tValue.Read(tStreamMaxReadLen),pFormat)
                                }
                                Write """"
                            }
                        } ElseIf pFormat["o" || ..hasObjContent(tValue,.pVisited,pFormat) {
                            Do nextProp
                            Write $$$ZENJSONPROP(tKey,pFormat)_":"
                            Set tSC = ..%ObjectToJSON(tValue,.pVisited, pLevel+1,pFormat)
                            Quit:$$$ISERR(tSC)
                        }
                    } ElseIf pFormat["a" {
                        Do nextProp
                        Write $$$ZENJSONPROP(tKey,pFormat)_":null"
                    }
                } ; end tKey object array loop
            } Else {
                #; scalar array elements
                Set tKey=""  For { Set tValue = pObject.GetNext(.tKey)  Quit:""=tKey
                    If (pFormat["e") || (tValue'="") {
                        Do nextProp
                        Write $$$ZENJSONPAIR(tKey,tValue,pFormat)
                    }
                } ; end tKey scalar array loop
            }
            If tPropCount'=0 {
                #; either we wrote at least one property or we wrote an empty '{' due to "o" mode or level zero
                If tIncludeWhitespace Set tIndent="", $P(tIndent,tTab,pLevel+1)="" Write tLF_tIndent
                Write "}"
            }
            Quit
        }
        #; else: main object is not a collection
        #; loop over properties using class meta-data
        Do ..getOrderedProps(tClass,.tProps)
        Set tSeq="" For { Set tSeq=$O(tProps(tSeq),1,tPropName)  Quit:""=tSeq
            Set tPrivate = +$$$comMemberKeyGet(tClass,$$$cCLASSproperty,tPropName,$$$cPROPprivate)
            Continue:tPrivate||(tPropName["%")
            Set tType = $$$comMemberKeyGet(tClass,$$$cCLASSproperty,tPropName,$$$cPROPtype)
            Set tClsType = $$$getClassType(tType)
            Set tClientType = $$$comClassKeyGet(tType,$$$cCLASSclientdatatype)
            Set tCollection = $$$comMemberKeyGet(tClass,$$$cCLASSproperty,tPropName,$$$cPROPcollection)
            If (tClsType '= "datatype") {
                #; Check for the case where we have a property declared as a %ListOf**
                If ($classmethod(tType,"%IsA","%Collection.AbstractList")) {
                    Set tCollection = "list"
                    If ($classmethod(tType,"%IsA","%Collection.AbstractListOfDT")) {
                        #; Reset object information for %ListOfDataTypes
                        Set tClientType = "VARCHAR"
                        Set tDataType = ""
                    }
                }
            } Else {
                Set tDataType=$Case(tClientType, "BOOLEAN":"b", "INTEGER":"n","NUMERIC":"n","FLOAT":"n", "TIMESTAMP":"u", "DATE":"d", "TIME":"t", :"")
            }
            Set tMultiDim = 0
            If (tCollection="array") {
                Set tCardinality = $$$comMemberKeyGet(tClass,$$$cCLASSproperty,tPropName,$$$cPROPcardinality)
                Set tInverse = $$$comMemberKeyGet(tClass,$$$cCLASSproperty,tPropName,$$$cPROPinverse)
                If ((tCardinality'="")&&(tInverse'="")) {
                    // treat relationship as list
                    Set tCollection = "list"
                }
            } ElseIf (tCollection = "") {
                Set tMultiDim = +$$$comMemberKeyGet(tClass,$$$cCLASSproperty,tPropName,$$$cPROPmultidimensional)
            }
            Continue:tMultiDim
            Set tValue = $property(pObject,tPropName)
            #; If the value is "" or $c(0) and we are NOT including empty properties, skip if we are not a collection, object or stream
            If (((tValue = "") || (tValue = $c(0))) && (pFormat'["e") && (tCollection = "") && $Case(tClientType, "HANDLE": 0, "CHARACTERSTREAM": 0, "BINARYSTREAM": 0, :1)) {
                Continue
            }
            // Write the property if not inhibited
            If (tCollection="list") {
                // list collection
                If '$IsObject(tValue) {
                    Set tCount = 0
                } Else {
                    Set tList = tValue
                    Set tCount = tList.Count()
                }
                If (pFormat["l" || tCount) {
                    Do nextProp
                    if ($$$comMemberArrayGet(tClass,$$$cCLASSproperty,tPropName,$$$cPROPparameter,"XMLNAME") '= "") {
                        Write $$$ZENJSONPROP($$$comMemberArrayGet(tClass,$$$cCLASSproperty,tPropName,$$$cPROPparameter,"XMLNAME"),pFormat)_":["
                    } else {
                        Write $$$ZENJSONPROP(tPropName,pFormat)_":["
                    }

                    For n = 1:1:tCount {
                        Set tValue = tList.GetAt(n)
                        Write:n>1 ","
                        If (tClientType = "HANDLE") {
                            #; object items
                            If $IsObject(tValue) {
                                Set tSC = ..%ObjectToJSON(tValue,.pVisited, pLevel+1, pFormat)
                                Quit:$$$ISERR(tSC)
                            } Else {
                                Write "null" ; not conditional because it has to hold the place in the list
                            }
                        } Else {
                            #; scalar list item ; converts $List to empty string!
                            Write $S((tDataType="b")&&(pFormat["e"):$S(tValue=1:"true",tValue=0:"false",1:"null")
                                , (tDataType="b"):$S(tValue:"true",1:"false")
                                , ((tDataType="n")||(pFormat["q"))&&$$$ZENJSISNUM(tValue):$$$ZENJSNUM(tValue)
                                , (tDataType="n")&&(tValue="")&&(pFormat["d"):"null"
                                , ($C(0)=tValue)||$ListValid(tValue):""""""
                                , 1:$$$ZENJSONSTR(tValue,pFormat))
                        }
                    }
                    Write "]"
                }
            }
            ElseIf (tCollection="array") {
                // array collection (object on client)
                If '$IsObject(tValue) {
                    Set tKey = ""
                } Else {
                    Set tArray = tValue
                    Set tKey = tArray.Next("")
                    If pFormat'["o" && (""'=tKey) {
                        #; look ahead to see if there is any content
                        Set tHasArrayContent=0, k=tKey  While (k '= "") { Set tValue = tArray.GetAt(k)
                            If (tClientType = "HANDLE") {
                                If $IsObject(tValue) {
                                    If ..hasObjContent(tValue,.pVisited,pFormat) Set tHasArrayContent=1  Quit
                                } ElseIf (pFormat["a") {
                                    Set tHasArrayContent=1  Quit
                                }
                            } Else {
                                If $S(tDataType="b":1
                                    , $C(0)=tValue||$ListValid(tValue):pFormat["e"
                                    //, "dtu"[tDataType:$S(pFormat["u":$$$ZENJSUSTR(..formatDateTime(tValue,tType,tDataType,pFormat)), 1:$$$ZENJSSTR(..formatDateTime(tValue,tType,tDataType,pFormat)))
                                    , 1:""'=tValue||(pFormat["e")) {
                                    Set tHasArrayContent=1  Quit
                                }
                            }
                            Set k = tArray.Next(k)
                        }
                    }
                }
                If (pFormat["o" || (""'=tKey && tHasArrayContent)) {
                    Do nextProp
                    if ($$$comMemberArrayGet(tClass,$$$cCLASSproperty,tPropName,$$$cPROPparameter,"XMLNAME") '= "") {
                        Write $$$ZENJSONPROP($$$comMemberArrayGet(tClass,$$$cCLASSproperty,tPropName,$$$cPROPparameter,"XMLNAME"),pFormat)_": {"
                    } else {
                        Write $$$ZENJSONPROP(tPropName,pFormat)_": {"
                    }

                    Set n = 0
                    While (tKey '= "") { Set tValue = tArray.GetAt(tKey)
                        If (tClientType = "HANDLE") {
                            #; object elements
                            If $IsObject(tValue) {
                                Set n = n+1
                                Write $S(n>1:",",1:"")_$$$ZENJSONPROP(tKey,pFormat)_":"
                                Set tSC = ..%ObjectToJSON(tValue,.pVisited, pLevel+1, pFormat)
                                Quit:$$$ISERR(tSC)
                            } ElseIf (pFormat["a") {
                                Set n = n+1
                                Write $S(n>1:",",1:"")_$$$ZENJSONPROP(tKey,pFormat)_":null"
                            }
                        } Else {
                            #; scalar array item ; converts $List to empty string!
                            Set tStr = $S((tDataType="b")&&(pFormat["e"):$S(tValue=1:"true",tValue=0:"false",1:"null")
                                , (tDataType="b"):$S(tValue:"true",1:"false")
                                , ((tDataType="n")||(pFormat["q"))&&$$$ZENJSISNUM(tValue):$$$ZENJSNUM(tValue)
                                , (tDataType="n")&&(tValue="")&&(pFormat["d"):"null"
                                , ($C(0)=tValue)||$ListValid(tValue):""""""
                                //, "dtu"[tDataType:$S(pFormat["u":$$$ZENJSUSTR(..formatDateTime(tValue,tType,tDataType,pFormat)), 1:$$$ZENJSSTR(..formatDateTime(tValue,tType,tDataType,pFormat)))
                                , 1:$$$ZENJSONSTR(tValue,pFormat))
                            If (pFormat["e") || (tStr'="""""") {
                                Set n = n+1
                                Write $S(n>1:",",1:"")_$$$ZENJSONPROP(tKey,pFormat)_":"_tStr
                            }
                        }
                        Set tKey = tArray.Next(tKey)
                    }
                    Write "}"
                }
            }
            ElseIf (tClientType = "HANDLE") {
                // object
                If $IsObject(tValue) {
                    If ..hasObjContent(tValue,.pVisited,pFormat) || (pFormat["o")  {
                        Do nextProp
                        if ($$$comMemberArrayGet(tClass,$$$cCLASSproperty,tPropName,$$$cPROPparameter,"XMLNAME") '= "") {
                            Write $$$ZENJSONPROP($$$comMemberArrayGet(tClass,$$$cCLASSproperty,tPropName,$$$cPROPparameter,"XMLNAME"),pFormat)_":"
                        } else {
                            Write $$$ZENJSONPROP(tPropName,pFormat)_":"
                        }

                        Set tSC = ..%ObjectToJSON(tValue,.pVisited, pLevel+1, pFormat)
                        Quit:$$$ISERR(tSC)
                    }
                } ElseIf (pFormat["a") {
                    Do nextProp
                    if ($$$comMemberArrayGet(tClass,$$$cCLASSproperty,tPropName,$$$cPROPparameter,"XMLNAME") '= "") {
                        Write $$$ZENJSONPROP($$$comMemberArrayGet(tClass,$$$cCLASSproperty,tPropName,$$$cPROPparameter,"XMLNAME"),pFormat)_":null"
                    } else {
                        Write $$$ZENJSONPROP(tPropName,pFormat)_":null"
                    }

                }
            }
            ElseIf (tClientType = "CHARACTERSTREAM") {
                If $IsObject(tValue) {
                    If tValue.Size || (pFormat["e") {
                        Do nextProp
                        if ($$$comMemberArrayGet(tClass,$$$cCLASSproperty,tPropName,$$$cPROPparameter,"XMLNAME") '= "") {
                            Write $$$ZENJSONPROP($$$comMemberArrayGet(tClass,$$$cCLASSproperty,tPropName,$$$cPROPparameter,"XMLNAME"),pFormat)_":"""
                        } else {
                            Write $$$ZENJSONPROP(tPropName,pFormat)_":"""
                        }

                        If tValue.Size {
                            #; Initialize stream read length, if needed
                            If '$data(tStreamMaxReadLen) Set tStreamMaxReadLen = ($$$MaxLocalLength\2)
                            Do tValue.Rewind()
                            While 'tValue.AtEnd {
                                Write $$$ZENJSONESCAPE(tValue.Read(tStreamMaxReadLen),pFormat)
                            }
                        }
                        Write """"
                    }
                } ElseIf (pFormat["a") {
                    Do nextProp
                    if ($$$comMemberArrayGet(tClass,$$$cCLASSproperty,tPropName,$$$cPROPparameter,"XMLNAME") '= "") {
                        Write $$$ZENJSONPROP($$$comMemberArrayGet(tClass,$$$cCLASSproperty,tPropName,$$$cPROPparameter,"XMLNAME"),pFormat)_":null"
                    } else {
                        Write $$$ZENJSONPROP(tPropName,pFormat)_":null"
                    }

                }
            }
            ElseIf (tClientType = "BINARYSTREAM") {
                Do nextProp
                if ($$$comMemberArrayGet(tClass,$$$cCLASSproperty,tPropName,$$$cPROPparameter,"XMLNAME") '= "") {
                    Write $$$ZENJSONPROP($$$comMemberArrayGet(tClass,$$$cCLASSproperty,tPropName,$$$cPROPparameter,"XMLNAME"),pFormat)_":null"
                } else {
                    Write $$$ZENJSONPROP(tPropName,pFormat)_":null"
                }

            }
            Else {
                #; scalar item ; converts $List to empty string!
                Set tStr = $S((tDataType="b")&&(pFormat["e"):$S(tValue=1:"true",tValue=0:"false",1:"null")
                    , (tDataType="b"):$S(tValue:"true",1:"false")
                    , ((tDataType="n")||(pFormat["q"))&&$$$ZENJSISNUM(tValue):$$$ZENJSNUM(tValue)
                    , (tDataType="n")&&(tValue="")&&(pFormat["d"):"null"
                    , ($C(0)=tValue)||$ListValid(tValue):""""""
                    //, "dtu"[tDataType:$S(pFormat["u":$$$ZENJSUSTR(..formatDateTime(tValue,tType,tDataType,pFormat)), 1:$$$ZENJSSTR(..formatDateTime(tValue,tType,tDataType,pFormat)))
                    , 1:$$$ZENJSONSTR(tValue,pFormat))
                If (pFormat["e") || (tStr'="""""") {
                    Do nextProp
                    if ($$$comMemberArrayGet(tClass,$$$cCLASSproperty,tPropName,$$$cPROPparameter,"XMLNAME") '= "") {
                        Write $$$ZENJSONPROP($$$comMemberArrayGet(tClass,$$$cCLASSproperty,tPropName,$$$cPROPparameter,"XMLNAME"),pFormat)_":"_tStr
                    } else {
                        Write $$$ZENJSONPROP(tPropName,pFormat)_":"_tStr
                    }

                }
            }
        } ; end properties loop
        Quit:$$$ISERR(tSC)
        If tPropCount'=0 {
            #; either we wrote at least one property or we wrote an empty '{' due to "o" mode or level zero
            If tIncludeWhitespace Set tIndent="", $P(tIndent,tTab,pLevel+1)="" Write tLF_tIndent
            Write "}"
        }
    }
    Catch ex {
        Set tSC = ex.AsStatus()
    }
    Quit tSC
nextProp
    If tPropCount=0 {
        If (tIncludeWhitespace && pLevel) Set tIndent="", $P(tIndent,tTab,pLevel+1)="" Write $S(pFormat["b":tLF_tIndent,1:" ")
        Write "{"
    } ElseIf tPropCount {
        Write ","
    } ; else tPropCount="" means we already did the starting '{' due to "o" mode
    Set tPropCount = tPropCount + 1
    If tIncludeWhitespace Set tIndent="", $P(tIndent,tTab,pLevel+2)="" Write tLF_tIndent
    Quit
}

And it works!

TEST>set x = ##class(test.msg.struct.TestXML).%New()
TEST>set x.statusId = "1111"
TEST>set x.service = "222"
TEST>do ##class(test.util.JsonProvider).%WriteJSONStreamFromObject(.obj1,.x,,,,"aelotuw")
TEST>w obj1.Read()
{
        "status_id":"1111",
        "service":"222"
}
TEST>

I didn't want to change system classes, so I thought to extend it and overrite what I need. For me is much clean this.

Hello.

I'm having the same problem, when I try to open a BPL class with the Atelier BPL Editor I get this error:

Bad editor input: org.eclipse.ui.part.FileEditorInput(/TEST/bp/Proceso.cls)

And the option "Open diagram editor" is not available.

I have this installed:

Eclipse IDE for JavaScript and Web Developers
Version: Photon Release (4.8.0)
Build id: 20180619-1200

 And the last version of Atelier in the marketplace (1.2).

What can I do? I have a macOS High Sierra v10.13.4, but it happens too on a Windows 10.

Thank you in advance.

Thank you very much for your answer. I don't know what algorithm uses openssl_public_encrypt.

I've tried this:

set json = "{""api_key"":""XXXXX"", ""id"":""1""}"
set file = ##class(%FileCharacterStream).%New()
set file.Filename = "public.key"
set key = file.Read(file.Size) 
set jsonEncrypt = $System.Encryption.RSAEncrypt(json, key)

But it doesn't work, it returns an empty string. I try to see the error using RSAGetLastError() and I don't get anything. The public.key has this format:

-----BEGIN PUBLIC KEY-----
......
......
......
......
-----END PUBLIC KEY-----

The line breaks are LF and it is in UTF-8. What format should the public key be in order to work in Ensemble? I am doing something wrong?

I have checked that question, but I don't understand what happens.

Finally I have used this instruction "openssl rsautl -in fileIn.txt -out fileOut-enc.txt -pubin -inkey public.key -encrypt" using $ZF(-100) and having OpenSSL installed on the server and it works.

I want to do it with Encryption methods, there must be a way to do this with COS and not using shell instructions, right?

Thanks a lot for all your support! It's been a pleasure to participate 😊 And congratulations to everyone! I think it was a tough competition, all articles were so great!

After executing your query, you need to move cursor and then you can get data:

SET SC = resultset.Prepare(sql) 
SET SC = resultset.Execute()
if (resultset.Next(.SC)) {
	quit:$$$ISERR(SC)
	set cnt = resultset.Data("CNT")
}
SET SC = resultset.Close()

According to the documentation, there is a parameter "pFormat" that has default value acelo, where:

  • c - output the ObjectScript-specific "_class" and "_id" properties

So, if you just call the transform like this, it should work:

set dynObj = ##class(%ZEN.Auxiliary.altJSONProvider).%ObjectToAET(person, , , "aelo")

Totally agree. One of the points that botherer me was the small size of all the elements, and the same colours in all the interface. I have the same opinion: less is more. And I think the new UI has too much information.

Like Jeffrey, I can't understand the rename of Services and Operations. And I don't understand neither why now you can disable or stop an element (maybe this option existed before, but I didn't realize until know 😅).

There are other points that I don't like:

  • I can't see when a production is ON or not. Neither the elements inside the production. In the current version, you can see this with strong colours, but now, at least in my case, I can't see it
  • In right menu, I can't distinguish configurations. They are all with white background, and too together, so I can't see when a config starts and when ends. The same happens with dropdown menus. They are white too, so it's difficult to see things correctly.

As a developer, changes are difficult to me, but I know that they are necessary. I'm not against this change, but I think with a few little improvements, it would be much better.

I have been testing this new UI and, like I said in this post, as a developer, changes for us are very difficult, so, I apologize for my complaints, but here they are:

  • I think the UI has too much information and elements are too small. Nowadays we have big screens, and there is a lot of space, but having all elements too close makes very difficult to see anything clearly.
  • Everything has the same colour, it's difficult to distinguish elements, menus, etc.
  • In the current version, when a production or an element is ON, you can see it very easy. But now, at least in my case, I can't see when an element is active, or disabled.
  • The right menu, for the settings, having white background and everything together, makes difficult to see where a configuration starts and where it ends. The same with dropdown menus, they are white, and they blurs into the background

I know that a change is needed, and I will adapt myself. But I think that with a few little improvements, this new UI can be a very good tool for all of us 😊

The name of the properties you are searching for are camel case, you need to change values used in "if" condition:

set itr = responseData.%GetIterator()
    while itr.%GetNext(.key, .value) {
      if key = "pureId"{
        set pResponse.pureID = value
      } elseif key = "portalUrl" {
        set pResponse.portalURL = value
      }
    }

That property doesn't exists in the class you are using as context. But in the rule editor, General tab, you have a section called Temporary Variables, you can create there, and reference it with @<name> in the rule. In your case, your assing will be:

assing @Namespace = Piece(AlertRequest.SourceConfigName,"|")

Here is the documentation:

Temporary Variables

User-specified temporary variables, which you can use in the rule definition. The variables must be separated by commas, for example:

FreeShippingValue,ShipMethod,PremierMember

You can reference a temporary variable in a rule definition by preceding the variable name with the @ (at sign) character, for example, @FreeShippingValue. You cannot use temporary variables outside the rule definition. To pass information to a transformation, you can instead use the RuleUserData property. For more information, see Selecting the Transformation and Target of a Send Action.

I reuse object that I get on first transformation and I transform it to another object, after a call.

This is the BPL that I use:

Class test.bp.TestProcess Extends Ens.BusinessProcessBPL
{

Storage Default
{
<Type>%Storage.Persistent</Type>
}

/// BPL Definition
XData BPL [ XMLNamespace = "http://www.intersystems.com/bpl" ]
{
<process language='objectscript' request='Ens.Request' response='Ens.Response' height='2100' width='2000' >
<context>
<property name='dataRsp' type='test.msg.GetDataResponse' instantiate='0' />
<property name='patient' type='HS.FHIR.DTL.vR4.Model.Resource.Patient' instantiate='0' />
<property name='fhirRsp' type='test.msg.SendResponse' instantiate='0' />
<property name='otherPatient' type='HS.FHIR.DTL.vR4.Model.Resource.Patient' instantiate='0' />
</context>
<sequence xend='200' yend='800' >
<code name='LOGASSERT 1' xpos='200' ypos='250' >
<![CDATA[ $$$LOGASSERT("1. Get data")]]>
</code>
<call name='GetData' target='TestBo' async='0' xpos='200' ypos='350' >
<request type='test.msg.GetDataRequest' >
</request>
<response type='test.msg.GetDataResponse' >
<assign property="context.dataRsp" value="callresponse" action="set" languageOverride="" />
</response>
</call>
<code name='LOGASSERT 2' xpos='335' ypos='600' >
<![CDATA[ $$$LOGASSERT("2. Transform to FHIR")]]>
</code>
<transform name='Transform 1' class='test.dtl.DataToPatient' source='context.dataRsp' target='context.patient' xpos='335' ypos='700' />
<code name='LOGASSERT 3' xpos='335' ypos='800' >
<![CDATA[ $$$LOGASSERT("3. Send to FHIR Repo 1")]]>
</code>
<call name='Send to FHIR Repo 1' target='TestBo' async='0' xpos='335' ypos='900' >
<request type='test.msg.SendRequest' >
<assign property="callrequest" value="##class(test.Util).generatePostFHIRReq(context.patient)" action="set" languageOverride="" />
</request>
<response type='test.msg.SendResponse' >
</response>
</call>
<code name='LOGASSERT 4' xpos='470' ypos='1150' >
<![CDATA[ $$$LOGASSERT("4. Transform to FHIR again (for other repo)")]]>
</code>
<!-- <transform name='REPEAT: Transform 1' class='test.dtl.DataToPatient' source='context.dataRsp' target='context.patient' xpos='335' ypos='700' /> -->
<transform name='Transform 2' class='test.dtl.DataToOtherPatient' source='context.patient' target='context.otherPatient' xpos='470' ypos='1350' />
<code name='LOGASSERT 5' xpos='470' ypos='1450' >
<![CDATA[ $$$LOGASSERT("5. Send to FHIR Repo 2")]]>
</code>
<call name='Send to FHIR Repo 2' target='TestBo' async='0' xpos='470' ypos='1550' >
<request type='test.msg.SendRequest' >
<assign property="callrequest" value="##class(test.Util).generatePostFHIRReq(context.otherPatient)" action="set" languageOverride="" />
</request>
<response type='test.msg.SendResponse' >
</response>
</call>
</sequence>
</process>
}

}

There is a commented line. If I activate this line (basically, repeat first transformation), then everything works.

The generatePostFHIRReq method:

ClassMethod generatePostFHIRReq(fhir As HS.FHIR.DTL.vR4.Model.Base.DomainResource) As test.msg.SendRequest
{
	#dim fhirReq As test.msg.SendRequest
	
	set fhirReq = ##class(test.msg.SendRequest).%New()
	set fhirReq.url = "/"_fhir.resourceType
	set fhirReq.body = ##class(%Stream.GlobalCharacter).%New()
	do fhirReq.body.Write(fhir.ToJSON().Read())
	
	return fhirReq
}

What I need is to send a FHIR resource to 2 different FHIR repositories. And for the second one I need to change some properties from de first transformation. I want to reuse the object obtained in first transformation, because sometimes the resource fot both FHIR repositories is the same.

Sure! FHIRCraft is built using InterSystems IRIS for Health and works through an interoperability production.

When you send a request (e.g. from the web UI), it goes through a REST service that transforms the input JSON into an IRIS message. From there, a business process handles the generation logic. Depending on the configuration, it can reuse existing resources from a FHIR repository or generate new ones.

The generated resources (like Patient, Observation, etc.) are optionally posted back to a FHIR server — either the default IRIS repository or any external one via REST.

It’s modular and easy to extend with new resource types. If you're curious, I wrote a short technical walkthrough here 😉