[AX TIP] Errores Interop CLR y nivel de transacciones

Hace un tiempo publiqué un artículo explicando las buenas prácticas recomendadas para el manejo de excepciones CLR y cómo mostrarlas correctamente en el InfoLog de Dynamics AX. Sin embargo olvidé entonces un detalle importante que hay que tener en cuenta al capturar estas excepciones, que es el nivel de transacciones en la base de datos (TTS Level).

En el siguiente código de ejemplo, nuestro try..catch NO funcionará. Si se produce un error en el try, por ejemplo, si el método get_Content() no existe en el objeto en tiempo de ejecución, la ejecución del código terminará directamente sin mostrar nada en el InfoLog, lo que no es muy deseable.

Esto es debido a que, para poder capturar una excepción CLR, el nivel de transacciones debe ser 0. O lo que es lo mismo, no podemos capturar errores del Interop dentro de una transacción. Para que este código funcione tendremos que re-escribirlo para que el manejo de ese objeto CLR genérico se realice antes de abrir la transacción.

CLRObject       obj;


ttsBegin;  // ttsLevel + 1

info(strFmt("TTS level: %1", appl.ttsLevel())); // TTS level: 1

try
{
    obj = response.get_Content();
    if (!CLRInterop::isNull(obj))
    {
        // ...
    }
}
catch(Exception::CLRError) // Este catch nunca se ejecutará porque ttsLevel > 0
{
    error(AifUtil::getClrErrorMessage());
}

ttsCommit; // ttsLevel - 1

En realidad, y debido al alto riesgo de que se produzcan errores CLR que deben capturarse y procesarse de forma especial, el manejo de objetos CLR debe encapsularse siempre en clases o métodos específicos donde quede claro su funcionamiento y aislado el riesgo de problemas.

[HowTo] Desplegar Microsoft Dynamics AX 7 en Azure

El nuevo Microsoft Dynamics AX, como sabemos, sólo está disponible en su versión para Azure por el momento. En cualquier caso, incluso cuando se publique la versión on-premise los entornos de desarrollo van a ser máquinas virtuales autocontenidas que podemos desplegar en Azure o montar en entornos locales.

Vamos a aprovechar que hoy Scott Guthrie (Executive VP Microsoft Cloud and Enterprise) ha anunciado la disponibilidad de la la preview pública durante la Convergence 2015 EMEA en Barcelona, para a ver cómo desplegar una de esas máquinas de desarrollo/demo y empezar a echar un vistazo a la plataforma, es muy fácil.

Microsoft Dynamics Lifecycle Services

Empezamos, como no puede ser de otra forma, en Lifecycle Services, sección Cloud-hosted environments, y seleccionamos Add. A partir de aquí seguimos el sencillo asistente para indicar el tipo de máquina que queremos desplegar, y en el último caso indicamos Azure como plataforma de despliegue. También odríamos elegir Locally para descargar el disco duro virtual de la máquina e instalarla en nuestros propios servidores.

Si seleccionamos Locally, se descarga el disco duro virtual y acaba el asistente. Si seleccionamos Azure, el asistente continúa y nos pide cuántas máquinas queremos desplegar y el tamaño de las mismas (ver tamaños de Azure aquí). Obviamente, cuanto mayor tamaño mejor rendimiento pero también mayor consumo de nuestros recursos de AX. En esta demo sólo voy a desplegar una máquina de desarrollo. Si elegimos desplegar máquinas de Build a la vez, ésta quedará configurada automáticamente mediante TFS, pero esto lo veremos en otro artículo.

Es posible que esto cambie en el futuro, pero en la versión previa de LCS disponible ahora mismo es necesario pulsar el botón Advanced settings e indicar nuestro login a VSO para que se pueda realizar a configuración del gestor de código fuente. Si no se incluye esta información el despliegue fallará. Podemos echar un vistazo a estas opciones avanzadas que nos permite configurar muchas propiedades de los servicios que se van a desplegar en Azure.

El proceso de despliegue tarda un buen rato, dependiendo de cuantas máquinas estemos creando. En cualquier caso puede tardar varias horas. Una vez terminado tendremos una página en LCS desde donde podremos realizar diferentes acciones.

  • Por un lado podemos conectar a la máquina virtual descargando un fichero RDP pulsando sobre el nombre de la máquina, desde donde podremos ejecutar las herramientas de desarrollo (Visual Studio).
  • En la página se nos muestran los usuarios y contraseñas utilizadas para el usuario Administrador.
  • Podemos iniciar y detener el entorno cuando queramos para ahorrar recursos de Azure mientras no la utilicemos.
  • Ofrece información sobre todos los recursos desplegados, que también podemos consultar desde el portal de administración de nuestra suscripción de Azure.
  • Pero lo más importante es que nos permite conectar directamente en el AX hospedado en este entorno. Recordad que AX es ahora una web, así que podemos conectar directamente a estas aplicaciones mediante el navegador web utilizando los enlaces disponibles en esta página (Login to Dynamics AX7, Login to Dynamics Retail, Login to Cloud Point of Sale) con los usuarios indicados.

Cuando la máquina se detiene desde esta sitio en LCS, las máquinas virtuales y servicios (el AOS) se detienen también, pero no el almacenamiento y otros servicios como el Directorio Activo, es normal ya que el almacenamiento sigue siendo utilizado aunque la máquina se pare (nuestros datos siguen en sus discos duros). Esto no es mayor problema ya que estos servicios son realmente baratos incluso ahora, antes de que se publiquen los packs de precios para Dynamics AX que nos permitirán ahorrarnos todos estos cálculos creando un plan de licencias por usuario sin tener en cuenta los recursos utilizados.

Una vez desplegada nuestra máquina de desarrollo, estamos listos para seguir con los siguientes artículos! 🙂

HOWTO: Exponer servicios de Microsoft Dynamics AX 2012 en un IIS externo

Para exponer los servicios web de Microsoft Dynamics AX 2012 fuera de nuestra red, es necesario instalar un servicio IIS que maneje las conexiones y la seguridad con “el mundo exterior“. La instalación de este servicio dependerá de nuestra red y lo ideal es que sea realizado por personal especializado en estas tareas (normalmente en un departamento de sistemas). Una vez instalado, la conexión de este servicio IIS con nuestra instancia de AX es muy sencilla.

Antes de empezar la instalación en sí, comprobamos algunos pre-requisitos.

  • El servicio IIS debe estar instalado y funcionando previamente. Si no lo está, para instalarlo hacemos lo siguiente:
    • La mayoría de pre-requisitos se pueden instalar directamente desde el instalador de Microsoft Dynamics AX 2012, pero si esto falla será necesario instalarlo manualmente.
    • Activar el rol Web Services en nuestro servidor y seguir el asistente.
    • Un reinicio es necesario al final del proceso.
    • Las opciones por defecto son suficientes para la instalación de Dynamics AX, pero probablemente será necesario realizar ajustes extra para adaptarlo a la seguridad que deseamos implementar en nuestra empresa, según el caso. No hay que olvidar que la finalidad de esta instalación es exponer este servicio a internet.
    • Puesto que el ejemplo es un servidor de pruebas, mantenemos las opciones por defecto, lo que implementará la seguridad nativa de Windows con Active Directory, solicitando un usuario válido durante la conexión.
  • Una vez instalado y asegurado nuestro servicio IIS, iniciamos el asistente de instalación de Dynamics AX 2012 en el mismo servidor y elegimos la opción Web Services on IIS, y seguimos las instrucciones. Durante el asistente, se nos solicita diversa información sobre nuestra instancia de AOS y las credenciales utilizadas para la conexión, como son:
    • Información sobre la instancia de AOS en sí: Nombre y puertos TCP/IP y WDSL
    • Cuenta de servicio configurada en AX (Business connector proxy)
    • Pool de IIS donde se instalarán y expondrán los servicios de AX
    • Las cuentas de servicio utilizadas para ejecutar nuestras instancias de AOS
  • El propio instalador configura la seguridad por defecto de la aplicación recién instalada en el pool de IIS seleccionado, pero podemos revisarla y configurarla manualmente si es necesario:
    • Se ha creado la aplicación MicrosoftDynamicsAXAif60 en el pool de IIS indicado
    • Se ha creado un nuevo grupo de usuarios local llamado Microsoft Dynamics AX Web Service Administrator incluyendo los usuarios que ejecutan los servicios AOS, según indicamos en el instalador.
    • Se le ha otorgado permiso a este grupo en la carpeta local AifWebServices del servidor IIS

También se ha creado un nuevo servicio en Microsoft Dynamics AX que podemos revisar en Administración del sistema > Configurar > AIF > Sitios web. Utilizaremos este sitio web para asociarlo a un puerto de entrada para poder exponer métodos en nuestros servicios, de esta forma:

  • Crear un nuevo puerto de entrada y seleccionar
    • Adaptador: HTTP
    • URL: Seleccionar la aplicación recién creada de la lista
  • Añadir las operaciones de servicio que se desean exponer mediante el botón Service operations
  • Realizar el resto de configuraciones requeridas en el puerto de entrada, como validaciones o restricciones que vayamos a necesitar. En mi caso voy a limitar las conexiones a un grupo de usuario de AX y a una sola empresa.

Como se puede ver en las imágenes a continuación, las operaciones expuestas de este modo pueden ser consumidas desde una aplicación externa en Visual Studio, a través de la aplicación creada en nuestro IIS:

Espero que este manual paso a paso haya sido útil y pueda servir de referencia para futuras instalaciones 😉

[HOWTO] Impersonar otro usuario para ejecutar código en X++

A pesar de que esto no es habitual y va contra unas cuentas Best Practices, en algunos casos muy específicos podemos necesitar ejecutar un framento de X++ (una llamada a un método) en el contexto de un usuario que no es el que está ejecutando la sesión actual, ya sea una sesión de cliente o un proceso Batch. Para ejecutar una llamada a un método con un usuario concreto, usamos este código:

// ...

// Usuario que va a ejecutar el método
UserId postingUserId = parms.PostingUserId != '' ? parms.PostingUserId : curUserId();

new RunAsPermission(postingUserId).assert();

// Llamada a: MyClass.myClassMethod(methodParm1, methodParm2)

// BP Deviation Documented
runAs(postingUserId, classNum(MyClass), 'myClassMethod', [methodParm1, methodParm2]);

CodeAccessPermission::revertAssert();

// ...

Insisto en que esto no es habitual y tiene, como siempre que hacemos estas cosas, algunos riesgos de seguridad. Pero dejo aquí el código para buscarlo la próxima vez que lo necesite 😉

HOWTO: Depurar desde Visual Studio código X++ que se ejecuta en el servidor AX 2012

Gran parte del código X++ que desarrollamos en clases se ejecuta en la capa del servidor (Data Providers en informes, procesos Batch, SysOperation, …), lo que resulta un poco incómodo a la hora de depurar. Si ponemos un breakpoint desde el editor de X++ en MorphX en código que se ejecuta en el servidor, veremos como el depurador integrado nunca se detiene en este punto.

Preparar el entorno de desarrollo para poder depurar código del servidor desde Visual Studio (incluso el código X++, que en el servidor siempre se ejecuta como código CIL) nos obliga a tener en cuenta unos cuantos pre-requisitos, así que los voy a enumerar aquí para tenerlos a mano cuando nos hagan falta:

Pre-requisitos y consideraciones previas:

  • Asegurarse de que el código CIL se ha ejecutado completamente y sin errores. De otra forma, el ensamblado que queremos depurar puede no estar disponible en su última versión, sino en la última que se compiló sin errores.
  • Para depurar código remoto, ejecutar Visual Studio siempre como Administrador (con permisos elevados, haciendo click-derecho > Ejecutar como administrador). Si no, más adelante tendremos problemas de permisos.
  • La depuración remota desde Visual Studio debe hacerse en el mismo servidor donde está instalado el AOS, lo que nos obliga indirectamente a utilizar un entorno de desarrollo, ya que esta no es la configuración ideal para un AOS en producción.
  • En la configuración del AOS debe estar activada la opción Enable breakpoints to debug X++ code runing on this server (esto tampoco es nada recomendable en un AOS en producción).
  • Asociar un proceso al AOS para depurar pone el servidor en un estado extremadamente inestable, con un riesgo muy importante de que el servicio se reinicie inesperadamente. Por tanto es muy recomendable utilizar un servidor de desarrollo aislado para no molestar al resto de desarrolladores. Si utilizamos un sólo AOS para todos los desarrolladores, puede ser interesante tener otro AOS para la depuración remota.

Iniciar la depuración remota:

  • Iniciar Visual Studio en el servidor y con permisos elevados.
  • Si no se está mostrando ya, mostrar el Application Explorer (desde el menú Ver), lo que nos muestra el AOS en VS.

Continue Reading…

AX TIP: Ejecutar código X++ externo

Siguiendo con el hilo de mi anterior artículo, otro truco parecido consiste en la posibilidad de utilizar la clase XppCompiler para ejecutar manualmente un fragmento de código almacenado de forma externa, ya sea en la base de datos, en una variable, en ficheros de texto, etc.

Para ello podemos utilizar una sintaxis parecida a la siguiente:

static void JAEE_XppCompiler_Code(Args _args)
{
    XppCompiler comp;
   
    Source codigo =
        "InventLocationId findLocation(InventDimId _inventDimId)" +
        "{" +
        "    return InventDim::find(_inventDimId).InventLocationId;" +
        "}";
   
    InventDimId         inventDimId = "1879356425";
    InventLocationId    result;
   
    new ExecutePermission().assert();
   
    comp = new XppCompiler();
   
    if (!comp.compile(codigo))
        throw error("Código no válido.");
   
    result = runBuf(codigo, inventDimId);
   
    CodeAccessPermission::revertAssert();
   
    info(strFmt("Resultado: %1", result));
}

Tal como decía en el artículo anterior, utilizar manualmente este tipo de API es peligroso y debe ser asegurado. En aquel capítulo incluía algunos enlaces de interés para desarrollar código seguro.

Las posibilidades a la hora de utilizar esta técnica son muy diversas. Podemos utilizarlo para ejecutar pequeños snipets de código almacenados en la base de datos de forma que un usuario pueda realizar pequeñas funciones personalizables, o podemos ir mucho más allá. Por ejemplo en este blog de MSDN nos explican cómo, aprovechando estas mismas clases y ejecutándolas desde el .NET Business Connector, se puede hacer una aplicación de consola para ejecutar fragmentos de código X++ desde línea de comandos.