Voy a poner la respuesta que me han dado en el grupo general y que es una solución muy buena. Muchas gracias @Julian Matthews


Hola Kurro.


No estoy seguro de una función incorporada para esto, pero si quisieras tener la tuya propia:

Class Demo.FunctionSets.Example
{

ClassMethod Format(InputString As %String, Params... As %String) As %String
{
	Set OutputString = InputString
	For i = 1 : 1 : $GET(Params, 0){
		Set OutputString = $Replace(OutputString,"{"_i_"}",Params(i))
	}
	
	Quit OutputString
}

}

Y entonces:

Write ##Class(Demo.FunctionSets.example).Format("My name is {1} and I'm {2} years","Kurro","18")
My name is Kurro and I'm 18 years

Podeis ver la respuesta original en el siguiente enlace

Muchas gracias,

Efectivamente el problema estaba siendo originado porque la dirección al que se va a conectar es variable, por lo que no está configurado el componente con el parámetro de Server ni URL.

Lo he solucionado de la siguiente forma:
 

set ..Adapter.HTTPServer = pRequest.Url
Set URL = pRequest.Url_"/search"
set tHttpResponse = ##class(%Net.HttpResponse).%New()
set tSC = ..Adapter.SendFormDataArray(.tHttpResponse,"POST",tHttpRequest,,,URL)

if $$$ISERR(tSC) && (tHttpResponse="") $$$ThrowStatus(tSC)
// Comprobamos cual es el código de respuesta
set contenido = ""
while (tHttpResponse.Data.AtEnd = 0) { 
    set contenido = contenido_tHttpResponse.Data.Read() 
}

do pResponse.%JSONImport(contenido)
set pResponse.StatusCode = tHttpResponse.StatusCode

Muchas gracias por la respuesta.

Un saludo,
Kurro Lopez

Al final no era un problema de firewall.

El problema era que la instalación no compiló correctamente el código. No tomó la versión de ISC correctamente.

Estoy usando la versión WebTerminal-v4.9.3, en la linea 1507 hay una inicialización del parámetro iscProductVersion

<Parameter name="iscProductVersion">
<Description>
In older Cache versions, method "GetISCProduct" does not exists</Description>
<Expression>$case(
        ##class(%Dictionary.CompiledMethod).IDKEYExists("%SYSTEM.Version", "GetISCProduct"),
        1: $CLASSMETHOD("%SYSTEM.Version", "GetISCProduct"),
        : 2
    )</Expression>
</Parameter>

Después, en la linea 1611, comprueba cuál es la versión para asignar el role requerido:

set requiredRole = $case(..#iscProductVersion >= 4, 1: "%DB_IRISSYS", : "%DB_CACHESYS")

Pero, si compruebo cuál es mi versión, la respuesta es 3, en lugar de 4, por lo que está intentando asignar %DB_CACHESYS en lugar de %DB_IRISSYS, por lo que la compilación no termina.

w ##class(%SYSTEM.Version).GetISCProduct() 
3

Entonces, he modificado el fichero y cambiado la comparación ..#iscProductVersion para que compruebe si es mayor o igual a 3, y funciona.

En la linea 1730, hay otra comparación para definir el dbPrefix, por lo que he cambiado esta linea también.

set dbPrefix = $case(..#iscProductVersion >= 3, 1: "IRIS", : "CACHE")

Ahora, tengo Webterminal funcionando bien.

Nota: Estoy usando IRIS for Windows (x86-64) 2021.1 (Build 215U) Wed Jun 9 2021 09:39:22 EDT

Saludos,
Francisco Lopez

Muchas gracias Pierre-Yves,

Entonces, para nuestro servidor de desarrollo lo mejor sería hacer lo siguiente:

  1. Crear los Namespaces en IRIS para que genere la estrcutura tal y como lo tenemos ahora en Ensemble (directorios, etc...)
  2. Parar las BBDD de modo seguro en Ensemble
  3. Parar las BBDD de modo seguro en IRIS
  4. Copiar los ficheros CACHE.DAT en los directorios que hemos creado en IRIS
  5. Renombrar CACHE.DAT por IRIS.DAT
  6. Levantar las BBDD de IRIS para que carguen las nuevas
  7. Revisar los mapeos de librerías (si los tiene)
  8. Disfrutar de IRIS como debe ser wink

Muchas gracias por tu ayuda, me ha sido de gran utilidad. Ya contaré que tal ha ido la migración... son 15 namespaces a migrar, así que con paciencia y buena letra.

Un saludo,
Kurro

Totalmente de acuerdo, pero son requisitos del cliente porque no entiende como funcionan a veces las trazas y las borran bastante a menudo. Quieren tener tanto las alertas por email mas unas trazas que se almacenan de forma externa.

Se puede aconsejar, se puede informar al cliente... pero es lo que quiere

Gracias David

Muchas gracias Alberto,

Aunque he puesto que envía un email, también el proceso envía una traza a un proceso interno para el control de errores.

Quiero controlar si falla el email, quede registrado a través de la api de trazas, y si falla las trazas, que envíe un email. (si fallan los dos... pues ya veremos)

Por lo que voy a implementar la solución que ha propuesto Julian en la pregunta que he realizado en la comunidad en inglés.

Un saludo,

Kurro Lopez

Investigando un poco mas la documentación de ZEN.Template no resulta complicado implementar nuevos métodos.

Siguiendo los mismos pasos que para el asistente SOAP, incluye la siguiente entrada en la lista de links y tendrás nuevos asistentes.

Installer Wizard

"Installer Wizard": "${serverUrl}/isc/studio/templates/%25Installer.InstallerWizard.cls?Namespace=${namespace}${serverAuth}"
 

DeepSeek PI Wizard

"DeepSeek PI Wizard": "${serverUrl}/isc/studio/templates/%25DeepSee.Template.DeepSeeKPIWizard.cls?Namespace=${namespace}${serverAuth}"

Buenas David,

Desde Visual Code no se han implementado los wizards de la misma forma que están en Studio, muchos de estos asistentes estaban programados en exclusiva para Studio, otros estaban pensados para acceder desde Atelier, a través de su server template, como el asistente de SOAP.

Podrás incorporarlo en Visual studio siguiendo los siguientes pasos

Asistente para cliente SOAP

https://es.community.intersystems.com/post/trucos-y-consejos-de-vscode-a...

Supongo que poco a poco, la comunidad podrá ir aportando algunos trucos para tener lo mismo que en Atelier.

Un saludo,
Kurro

Esto es lo que ha devuelto el log

09/23/2021 16:04:36 *********************
Output from Web client with SOAP action = http://ws.myprovider.org/buscarInfo
<?xml version="1.0" encoding="UTF-8" ?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:s='http://www.w3.org/2001/XMLSchema'>
  <SOAP-ENV:Body><buscarInfo xmlns="http://ws.myProvider.salutic.org/"><idEspecialidad xsi:type="s:string">CT</idEspecialidad><centroSanitario xsi:type="s:string">CG</centroSanitario><infoAdicional xmlns:s01="http://ws.myProvider.salutic.org/" xsi:type="s01:infoAdicionalType"><ambulancia xsi:type="s:boolean">false</ambulancia><urgencia xsi:type="s:boolean">false</urgencia><gravedad xsi:type="s:boolean">false</gravedad><anestesia xsi:type="s:boolean">false</anestesia><claustrofobia xsi:type="s:boolean">false</claustrofobia></infoAdicional></buscarInfo></SOAP-ENV:Body>
</SOAP-ENV:Envelope>

09/23/2021 16:04:36 *********************
Input to Web client with SOAP action = http://ws.myProvider.org/buscarInfo

ERROR #6243: La solicitud HTTP a SOAP WebService ha devuelto una respuesta con CONTENT-TYPE inesperado: application/wsdl+xml.
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://ws.myProvider.org/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://ws.myProvider.org/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/">
<wsdl:documentation>Servicio Web para InfoOnline TEST</wsdl:documentation>
  <wsdl:types>
    <xsd:schema>
<xsd:import namespace="http://ws.myProvider.org/" schemaLocation="InfoOnline.xsd"/>
</xsd:schema>
  </wsdl:types>
  <wsdl:message name="buscarInfoSoapOut">
    <wsdl:part name="buscarInfoResult" element="tns:buscarInfoResponse">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="buscarInfoSoapIn">
    <wsdl:part name="parameters" element="tns:buscarInfo">
    </wsdl:part>
  </wsdl:message>
  <wsdl:portType name="InfoOnlineWSSoap">
    <wsdl:operation name="buscarInfo">
<wsdl:documentation>Solicita informacion para un paciente</wsdl:documentation>
      <wsdl:input message="tns:buscarInfoSoapIn">
    </wsdl:input>
      <wsdl:output message="tns:buscarInfoSoapOut">
    </wsdl:output>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="InfoOnlineWSSoap" type="tns:InfoOnlineWSSoap">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="buscarInfo">
      <soap:operation soapAction="http://ws.myProvider.org/buscarHueco" style="document"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="InfoOnlineWS">
<wsdl:documentation>Servicio Web Seguro  (Pruebas) para InfoOnline (TEST) </wsdl:documentation>
    <wsdl:port name="InfoOnlineWSSoap" binding="tns:InfoOnlineWSSoap">
      <soap:address location="https://urlprovider.com/services/SIU"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>
**** SOAP client return error. method=buscarInfo, action=http://ws.myProvider.org/buscarInfo
     ERROR #6243: La solicitud HTTP a SOAP WebService ha devuelto una respuesta con CONTENT-TYPE inesperado: application/wsdl+xml.

Nota: Por motivos de confidencialidad, se ha modificado la dirección del proveedor y algunos detalles mas, pero esta es la respuesta obtenida.

He sobreescrito el método %OnSOAPResponse para ver si obtenía algo, y ya viene con el error

 Method %OnSOAPResponse(mode As %String, client As %SOAP.WebClient, action As %String, oneWay As %Boolean, method As %String, requestStream As %BinaryStream, responseStream As %BinaryStream, sc As %Status)
{
Quit
}

entonces, no debería de ser un problema de la cabecera de salida, sino mas bién las cabeceras de entrada. ¿O es que intenta recuperar el WSDL para hacer la operación y ahí es donde está el problema?

Un saludo,
Kurro

Hola David,

No se donde se establece ese valor.

El Business Operation se creó usando el wizard y lo que se modificó en los métodos, es que antes de hacer el Invoke a cada uno de los métodos del WS, modifica el namespace y el Location según a que proveedor va a realizar la consulta.

Todos los proveedores tienne la misma estructura y métodos iguales, varían el Namespace y la URL.

He probado a incluir la siguiente linea:

Method MiMetodo(pRequest As MyMessageWS.RequestbuscarInfoRequest, Output pResponse As MyMessageWS.RequestbuscarInfoResponse) As %Library.Status
{
    do ..preparaOperacion(pRequest)
    Set tSC = ..Adapter.InvokeMethod("buscarInfo",.info,pRequest.idEspecialidad,pRequest.listaActos,pRequest.centroSanitario,pRequest.infoAdicional)
    Quit:$$$ISERR(tSC) tSC
    Set tSC = pRequest.NewResponse(.pResponse)  Quit:$$$ISERR(tSC) tSC
    Set pResponse.InfoCentro=$get(info)
    Quit $$$OK
}

Method preparaOperacion(pRequest As MyMessageWS.Request.base) As %Status
{
 Set ..Adapter.%Client.Namespace = pRequest.Namespace
 Set ..Adapter.%Client.Location = pRequest.Url
 Set ..Adapter.%Client.ContentType = "application/wsdl+xml"
 Quit $$$OK
}

He invocado al proveedor directamente para que me dé el WSDL y, efectivamente, responde con un fichero wsdl+xml

A ver si con esta explicación puedes ayudar mejor.

Un saludo,
Kurro