客户端为 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
数据流
- 服务加载或创建 (
new System.Drawing.Bitmap()
) System.Drawing.Image
对象并将其存储到 DataDynamics.ActiveReports.ActiveReport.Watermark
- 然后
DataDynamics.ActiveReports.ActiveReport
被压缩并发送到客户端应用程序
- 客户端使用
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
编译的,数据流可以正常工作。
问题
总结一下:
- AppPool
v4.0
、客户端 v3.5
、服务 v3.5
= 错误
- AppPool
v2.0
、客户端 v3.5
、服务 v3.5
= 无错误
- AppPool
v4.0
、客户端 v4.x
、服务 v4.x
= 无错误
由于选项 2 和 3 现在不是一个选项,我虚心询问是否有人知道如何解决选项 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>
向 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;
}
请注意,更好的解决方案是调整您的服务和客户端框架版本,而不是弄乱二进制内存流。
设置
服务
使用 IIS 7.5
并将应用程序池设置为 v4.0 integrated
,使用 .NET Framework v3.5
客户
使用 WinForms
客户端编译 .NET Framework v3.5
数据流
- 服务加载或创建 (
new System.Drawing.Bitmap()
)System.Drawing.Image
对象并将其存储到DataDynamics.ActiveReports.ActiveReport.Watermark
- 然后
DataDynamics.ActiveReports.ActiveReport
被压缩并发送到客户端应用程序 - 客户端使用
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
编译的,数据流可以正常工作。
问题
总结一下:
- AppPool
v4.0
、客户端v3.5
、服务v3.5
= 错误 - AppPool
v2.0
、客户端v3.5
、服务v3.5
= 无错误 - AppPool
v4.0
、客户端v4.x
、服务v4.x
= 无错误
由于选项 2 和 3 现在不是一个选项,我虚心询问是否有人知道如何解决选项 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>
向
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;
}
请注意,更好的解决方案是调整您的服务和客户端框架版本,而不是弄乱二进制内存流。