Errores Interop CLR y manejo de Infolog en Microsoft Dynamics AX 2012

Al trabajar con objetos del framework .NET (algo muy común en AX 2012), debemos tener en cuenta el tratamiento de errores CLR. El tratamiento de errores en Dynamics AX es transparente y no necesita dedicarle demasiada atención durante el desarrollo en X++, pero cuando interviene el Interop con .NET, el manejo de los errores CLR se debe especificar de forma explícita.

El código que suelo utilizar habitualmente (copiado y pegado de mi repositorio personal) como punto de inicio es el siguiente:

static void JAEE_CLRError(Args _args)
{
    System.Exception ex;
   
    new InteropPermission(InteropKind::ClrInterop).assert();  
   
    try
    {
        System.Int32::Parse("JAEE");  // Error: no se puede convertir un texto a Int32
    }
    catch (Exception::CLRError)
    {
        ex = ClrInterop::getLastException();
        if (ex != null)
        {
            info(ex.get_Message());
            ex = ex.get_InnerException();
            if (ex != null)
                error(ex.ToString());
        }
    }    
    catch (Exception::Internal)
    {
        ex = ClrInterop::getLastException();
        if (ex != null)
            info(ex.get_Message());
    }  
   
    CodeAccessPermission::revertAssert();
}

El resultado que muestra es este:

Error CLR Interop

Este es un manejo de errores bastante completo y el resultado es válido para guardar el InfoLog en una tabla a modo de Log para mostrarlo más tarde, o para usarlo en procesos por lotes, etc. En general siempre que necesitemos guardar el error con el máximo de información posible para su posterior diagnóstico.

Sin embargo no es muy amigable si lo que deseamos es mostrar el error al usuario para que pueda actuar directamente sobre él. Para eso podemos usar una versión simplificada de este código, y cambiar la llamada a ToString() por get_Message(), de esta forma:

    //...
    catch (Exception::CLRError)
    {
        ex = ClrInterop::getLastException();
        if (ex != null)
        {
            ex = ex.get_InnerException();
            if (ex != null)
                error(ex.get_Message()); // Message
        }
    }    
    //...

El resultado es mucho más amable:

Error CLR Interop

Existe una clase que facilita la reutilización de este código y produce el mismo resultado con un código más fácil de leer. Aunque está guardado en la clase AifUtil, puesto que es un método estático puede utilizarse desde cualquier parte, aunque no estemos trabajando con AIF (deberían haber creado una clase específica para el manejo de errores CLR, pero esto es lo que hay), de esta forma:

    //...
    catch (Exception::CLRError)
    {
        error(AifUtil::getClrErrorMessage());
    }  
    //...

EXTRA

Por tenerlo aquí guardado para posterior referencia, la salida del InfoLog puede guardarse en un campo de una tabla, y recuperarse después para ver su contenido. De esta forma:

static void JAEE_InfologPackUnpack(Args _args)
{
    TableEjemplo    table;
   
    // Ejemplo
    setPrefix("Prueba");
    info("Mensaje");
    warning("Warning");
    error("Error");
   
    // Guardar InfoLog
    table.FieldContainer = infoLog.infoLogData();
    table.insert();
   
    // Mostrar InfoLog guardado
    select firstOnly table;
   
    infoLog.view(table.FieldContainer);
}

Este es uno de esos post que yo llamo de “autoayuda“, porque en realidad los escribo para tener aquí el código y saber dónde acudir cuando lo necesite la próxima vez, pero seguro que le sirve a alguien más 🙂