简体   繁体   English

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

[英]Decompress a GZip Stream in Dynamics AX X++

I'm attempting to deflate a .NET GZIPStream in X++ but I'm running into a bug. 我正在尝试在X ++中压缩.NET GZIPStream,但遇到了一个错误。 The .NET code to create the string is pretty simple: 创建字符串的.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;
    }

The AX side will get the compressed string via some web service call. AX端将通过某些Web服务调用获得压缩的字符串。 The X++ code I have currently is below, but I'm getting the error "Object 'CLRObject' could not be created" when creating the StreamWriter. 我目前的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);
}

Edit : building on @robert-allen 's answer below, the correct code to accomplish this in AX is: 编辑 :建立在下面的@ 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);
}

Can you add a try catch around your code to see the exact message that you get, because there are 2 errors in Ax that don't really tell you what is going on: 您是否可以在代码周围添加try catch以查看得到的确切消息,因为Ax中有2个错误并不能真正告诉您发生了什么:

  • An exception has been thrown by the target of an invocation 调用的目标已引发异常
  • CLRObject could not be created 无法创建CLRObject

The first one is .net having trouble in a constructor of the .NET type and can have various reasons so the exception details should be able to help you along. 第一个是.net在.NET类型的构造函数中遇到问题,并且可能有多种原因,因此异常详细信息应该能够为您提供帮助。

The second one can be more difficult because it can be assemblies that cannot be found. 第二个可能更困难,因为它可能是找不到的程序集。 But in that case you might have information as to what file is being looked for and should lead you to the place where Ax expects them to be. 但是在那种情况下,您可能会了解正在寻找什么文件的信息,并且应该将您带到Axe期望它们所在的位置。 (And for that reason it is certainly a good idea to start by putting your assembly in the Global Assembly case. (因此,将您的程序集放入“全球程序集”案例中无疑是一个好主意。

To get more information out of the exception, you can do the following: 要从异常中获取更多信息,您可以执行以下操作:

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

The problem with Kenny Saelen's approach is that many CLRInterop errors are of such a level that they break through the Dynamics AX X++ catch clause regardless of it being specified to catch an Exception::CLRError. Kenny Saelen方法的问题在于,许多CLRInterop错误都达到了这样的水平,即它们突破了Dynamics AX X ++ catch子句,无论它是否被指定为捕获Exception :: CLRError。 I've encountered this before when using the System.IO methods such as file moves/deletes. 我在使用System.IO方法之前遇到过这种情况,例如文件移动/删除。

One way to better see your error (since you cant catch it properly in X++) is to rewrite your job in .NET code and use a .NET catch block which is perfectly capable of catching that error. 更好地查看错误的一种方法(因为您无法在X ++中正确捕获它)是用.NET代码重写您的作业,并使用一个完全能够捕获该错误的.NET catch块。 Build the objects in a C# console application and recreate the same behavior encapsulated in a .NET try/catch. 在C#控制台应用程序中生成对象,然后重新创建封装在.NET try / catch中的相同行为。

Something like this: 像这样的东西:

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();
    }
}

Let me know if that works for you Spankachu. 让我知道这是否对您有用。

Cheers 干杯

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM