Axapta 在Dynamics AX X+中解压缩GZip流+;

Axapta 在Dynamics AX X+中解压缩GZip流+;,axapta,x++,ax,Axapta,X++,Ax,我试图在X++中压缩.NETGzipstream,但遇到了一个bug。创建字符串的.NET代码非常简单: private string CompressString() { string stringToCompress = "Some data here"; string result = string.Empty; using (MemoryStream output = new MemoryStream())

我试图在X++中压缩.NETGzipstream,但遇到了一个bug。创建字符串的.NET代码非常简单:

    private string CompressString()
    {
        string stringToCompress = "Some data here";
        string result = string.Empty;

        using (MemoryStream output = new MemoryStream())
        using (GZipStream gzip = new GZipStream(output, CompressionMode.Compress, true))
        using (StreamWriter writer = new StreamWriter(gzip))
        {
            writer.Write(stringToCompress);
            writer.Close();
            result = Convert.ToBase64String(output.ToArray());
        }

        return result;
    }
AX端将通过一些web服务调用获取压缩字符串。下面是我当前拥有的X++代码,但我在创建StreamWriter时遇到错误“无法创建对象'CLRObject'

static void Job2(Args _args)
{
   System.String decodedString;
   System.Byte[] buffer;
   System.IO.Compression.GZipStream gzip;
   System.IO.StreamWriter writer;
   System.IO.MemoryStream output;
   InteropPermission permission;
   CLRObject ex;

   str compressedString ="Compressed data here";
   ;

   ttsBegin;
   permission = new InteropPermission(InteropKind::ClrInterop);
   permission.assert();

   buffer = System.Convert::FromBase64String(compressedString);
   output = new System.IO.MemoryStream(buffer);
   gzip = new System.IO.Compression.GZipStream(output, System.IO.Compression.CompressionMode::Decompress);

   try {
       //Error here: "Object 'CLRObject' could not be created"
       writer = new System.IO.StreamWriter(gzip);
       writer.Write(decodedString);
       writer.Close();

       CodeAccessPermission::revertAssert();
   } 
   catch (Exception::CLRError) {
       //Code never executes past this point 
       ex = CLRInterop::getLastException();

       while(ex != null) {
           error(ex.ToString());
           ex = ex.get_InnerException();
       }
   }

   ttsCommit;
   info(decodedString);
}
编辑:基于@robert allen下面的答案,在AX中实现这一点的正确代码是:

static void Job2(Args _args)
{
   System.String decodedString;
   System.Byte[] buffer;
   System.IO.Compression.GZipStream gzip;
   System.IO.StreamReader reader; //<-- Reader instead of writer
   System.IO.MemoryStream output;
   InteropPermission permission;
   CLRObject ex;

   str compressedString ="Compressed data here";
   ;

   ttsBegin;
   permission = new InteropPermission(InteropKind::ClrInterop);
   permission.assert();

   buffer = System.Convert::FromBase64String(compressedString);
   output = new System.IO.MemoryStream(buffer);
   gzip = new System.IO.Compression.GZipStream(output, System.IO.Compression.CompressionMode::Decompress);

   try {
       //Reader code changes
       reader = new System.IO.StreamReader(gzip);
       decodedString = reader.ReadToEnd();
       reader.Close();
       //End reader code changes

       CodeAccessPermission::revertAssert();
   } 
   catch (Exception::CLRError) {
       //Code never executes past this point 
       ex = CLRInterop::getLastException();

       while(ex != null) {
           error(ex.ToString());
           ex = ex.get_InnerException();
       }
   }

   ttsCommit;
   info(decodedString);
}
静态无效作业2(Args\u Args)
{
系统。字符串解码字符串;
字节[]缓冲区;
System.IO.Compression.GZipStream gzip;

System.IO.StreamReader;//您能否在代码周围添加一个try catch以查看您得到的确切消息,因为Ax中有两个错误并不能真正告诉您发生了什么:

  • 调用的目标已引发异常
  • 无法创建CLR对象
第一个是.net在.net类型的构造函数中遇到问题,可能有各种原因,因此异常详细信息应该能够帮助您

第二个可能会更困难,因为它可能是找不到的程序集。但是在这种情况下,您可能有关于正在查找的文件的信息,并且应该将您引导到Ax希望它们位于的位置。(因此,首先将您的程序集放在全局程序集案例中当然是一个好主意。)

要从异常中获取更多信息,可以执行以下操作:

catch (Exception::CLRError)
{
     ex = ClrInterop::getLastException();
     if (ex != null)
     {
        ex = ex.get_InnerException();
        while (ex != null)
        {
            error(ex.ToString());
            ex = ex.get_InnerException();
        }
    }
}

Kenny Saelen的方法的问题是,许多CLR互操作错误的级别都会突破Dynamics AX X++catch子句,而不管它被指定用于捕获异常::CLRRERROR。我以前在使用System.IO方法(如文件移动/删除)时遇到过这种情况

更好地查看错误的一种方法(因为在X++中无法正确捕获错误)是在.NET代码中重写作业,并使用完全能够捕获错误的.NET catch块。在C#console应用程序中构建对象,并重新创建封装在.NET try/catch中的相同行为

大概是这样的:

static void Main(string[] args)
{
    System.String decodedString;
    System.Byte[] buffer;
    System.IO.Compression.GZipStream gzip;
    System.IO.StreamWriter writer;
    System.IO.MemoryStream output;

    string compressedString = "sample";

    buffer = System.Convert.FromBase64String(compressedString);
    output = new System.IO.MemoryStream(buffer);
    gzip = new System.IO.Compression.GZipStream(output, System.IO.Compression.CompressionMode.Decompress);

    try
    {
        writer = new System.IO.StreamWriter(gzip);
        writer.Write(decodedString);
        writer.Close();

        Console.Write(decodedString);
        Console.ReadKey();
    }
    catch (Exception ex)
    {
        Console.Write(ex.Message);
        Console.ReadKey();
    }
}
让我知道这对你是否有效


干杯

您的AX的client\bin目录和/或GAC中是否都有合适的DLL?我只能假设我与客户端在同一台计算机上运行Visual Studio。是否有我应该查找的特定内容?抱歉,我猜错误消息不清楚。原因是“无法创建对象'CLROBOCT'”。我将更新该问题以使其更准确。请尝试将适当的DLL与AX32放在同一文件夹中。我公司的另一位开发人员建议,该错误可能是代码访问权限错误,但在添加断言时我看不出有什么不同。我已将调用包装在Try/Catch中(上面更新的代码),但是catch块从未运行。尝试运行
writer=new System.IO.StreamWriter(gzip)后,代码立即停止执行;
。我公司的另一位开发人员建议,该错误可能是代码访问权限错误,但我在添加断言时看不出有什么区别。啊,太好了。这正是我所需要的。结果(令人尴尬地)当我应该使用
System.IO.StreamWriter
时,我使用了
System.IO.StreamWriter
。异常非常明显(不是一个可写流)。将AX代码切换到相同的版本修复了问题。