客户端为 3.5 时,apppool 4.0 中的活动报告/System.Drawing.Image 出错

Error with active reports / System.Drawing.Image in apppool 4.0 while client is 3.5

设置

服务

使用 IIS 7.5 并将应用程序池设置为 v4.0 integrated,使用 .NET Framework v3.5

编译代码

客户

使用 WinForms 客户端编译 .NET Framework v3.5

数据流

  1. 服务加载或创建 (new System.Drawing.Bitmap()) System.Drawing.Image 对象并将其存储到 DataDynamics.ActiveReports.ActiveReport.Watermark
  2. 然后 DataDynamics.ActiveReports.ActiveReport 被压缩并发送到客户端应用程序
  3. 客户端使用 DataDynamics.ActiveReports.Viewer.Viewer 加载该对象并显示它。

症状

在初始设置中,客户端会得到找不到程序集的异常System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

我个人希望如果服务应用程序和客户端应用程序都使用 .NET Framework v3.5 编译,那么它们将使用 System.Drawing, Version=2.0.0.0..

如果 v2.0 中的应用程序池是 运行,则数据流工作正常。

如果 v4.0 中的应用程序池是 运行,则服务和客户端是使用 CLR4 编译的,数据流可以正常工作。

问题

总结一下:

  1. AppPool v4.0、客户端 v3.5、服务 v3.5 = 错误
  2. AppPool v2.0、客户端 v3.5、服务 v3.5 = 无错误
  3. AppPool v4.0、客户端 v4.x、服务 v4.x = 无错误

由于选项 2 和 3 现在不是一个选项,我虚心询问是否有人知道如何解决选项 1。

到目前为止我尝试过的事情

  1. 将显式汇编版本放入 Web.config

    中的 compilation 部分
    <compilation defaultLanguage="c#" debug="true">
        <!--<assemblies>
            <add assembly="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
        </assemblies>-->
    </compilation>
    
  2. compilation 元素添加显式框架版本属性 targetframework="3.5"

这是一个很奇怪的问题。我的猜测是它与图像的序列化有关。只是为了测试,您能否将图像保存为 PNG 或 JPG 文件,然后让 AR 从文件中加载它。

因此,当前问题的根本原因在于主动报告本身的实施。如果使用 DataDynamics.ActiveReports.ActiveReport.Document object is being saved into a stream by a call to the Save(Stream) 方法,当前对象 ResourceManager 内容将以二进制格式写入流。 ResourceManager 包含将作为程序集字符串写入流的程序集引用。

因此,当在客户端打开流时,Load(Stream) 方法将尝试恢复那些导致所述错误的程序集引用。

以下 hack 是我想出的解决该问题的方法。

static byte[] ReplaceAssemblyRef(MemoryStream stream)
{
    byte[] buffer = stream.GetBuffer();
    byte[] search = new byte["System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".Length * sizeof( char )];
    byte[] replace = new byte["System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".Length * sizeof( char )];
    Buffer.BlockCopy( "System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".ToCharArray(), 0, search, 0, search.Length );
    Buffer.BlockCopy( "System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a".ToCharArray(), 0, replace, 0, replace.Length );

    IEnumerable<int> indicies = Enumerable.Range( 0, buffer.Length - search.Length + 1 );

    for( int i = 0; i < search.Length; i++ )
        indicies = indicies.Where( n => buffer[n + i] == search[i] ).ToArray();

    foreach( int i in indicies )
        Buffer.BlockCopy( replace, 0, buffer, i, replace.Length );

    return buffer;
}

请注意,更好的解决方案是调整您的服务和客户端框架版本,而不是弄乱二进制内存流。