引用 x86 DLL 时,在 Vista x64 上的 Visual Studio 2008 中创建 WCF 服务库很麻烦。调用 32 位 DLL 的服务需要具有 x86 平台目标才能在 64 位操作系统上运行。执行此操作时,当您尝试调试服务时,WcfSvcHost 会引发 BadImageFormatException。有一个关于 MS 连接的错误报告。我使用的解决方法是将WcfSvcHost 核心标记为 32-bit。
明显问题
我遇到的主要问题是这个第三方本机 32 位 DLL 无法使用某些 WCF 主机加载。调用使用第三方 DLL的服务操作时,我收到以下错误:
System.TypeInitializationException:“”的类型初始化程序引发了异常。
.ModuleLoadExceptionHandlerException:在导致 C++ 模块加载失败的主要异常之后发生了嵌套异常。
System.BadImageFormatException:该模块应包含程序集清单。(来自 HRESULT 的异常:0x80131018)
嵌套异常:
句柄无效。(来自 HRESULT 的异常:0x80070006 (E_HANDLE))
当 WcfSvcHost 启动时不会引发此异常,它会在调用引用 32 位 DLL 的服务操作时引发。非常有趣的是,在控制台应用程序上使用相同的 app.config 托管相同的服务没有例外,并且运行良好:
using (ServiceHost host = new ServiceHost (typeof (MsgBrokerService))) {
host.Open ();
Console.WriteLine ("running");
Console.ReadLine ();
此异常发生在以下情况之后:
“WcfSvcHost.exe”(托管):已加载“C:\Windows\WinSxS\x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.3053_none_d08d7bba442a9b36\msvcm80.dll”
同样,控制台应用程序没有异常并加载相同的 DLL:
“ConsoleApp.vshost.exe”(托管):已加载“C:\Windows\WinSxS\x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.3053_none_d08d7bba442a9b36\msvcm80.dll”
更新 #1:控制台应用程序和 WcfSvcHost.exe 主机进程都在同一会话和登录用户(我)下运行。我已将 WcfSvcHost.exe 复制到服务目录,手动启动并遇到相同的结果。我还检查了 Windows 事件日志以获取更多信息并使用sxstrace,但没有记录任何内容。
运行 Process Explorer,我已经验证了两个进程之间的以下内容相同:
- 图像:32 位
- 当前目录
- 用户/SID
- 会议
- 安全性(组被拒绝,特权被禁用)
运行 Process Monitor 并配置符号,我看到 WcfSvcHost 查找以下注册表和文件,而控制台主机没有。Process Monitor 记录了很多数据,我不确定我在寻找什么:(。
HKLM \ Software \ Microsoft \ Fusion \ PublisherPolicy \ Default \ Policy.8.0.MSVCM80_B03F5F7F11D50A3A C:\ Windows \ assembly \ Gac_32 \ MSVCM80 \ 8.0.50727.3053_CM:\ Windows \ alifting \ Gac_MSIL \ MSVCM80 \ 8.0.50727.3053_B03F5F7.3053_B03F5F7F11D50A3A C:\ Windows\程序集\GAC\msvcm80\8.0.50727.3053__b03f5f7f11d50a3a
更新 #2:当服务托管在IIS 6/Windows Server 2003 上的生产环境中时,也会发生同样的异常。
更新 #3:第 3 方 32 位 .NET 程序集是StreamBase API:
- sbclient.dll(托管)
- monitor.netmodule(托管)
- dotnetapi.dll(非托管)
- pthreads-vc8.dll(非托管)
更新 #4:添加清单但未成功:
- 验证 dotnetapi.dll 和 pthreads-vc8.dll 有 RT_MANIFEST。sbclient.dll .NET 程序集没有清单
- 从 GAC 中删除 sbclient.dll
- 注册 sbclient.dll 以跳过验证
- 通过mt.exe将清单添加到 sbclient.dll 和 monitor.netmodule
- 添加了经过验证的清单,并且在测试期间加载了预期的文件(通过 Visual Studio - 调试模块窗口)
- 在 BackgroundWorker.OnDoWork() 下会抛出相同的 BadImageFormatException,调用堆栈显示对 dotnetapi.dll...DefaultDomain.Initalize() 的调用。
我已经验证 msvcm80.dll 没有清单,我相信这是加载的唯一没有清单的文件:)
有趣的发现
当我在Reflector加载 monitor.netmodule 时,它说:
“monitor.netmodule”不包含程序集清单。
即使它显示错误,Reflector 仍然能够反汇编托管代码。