WcfSvcHost和IIS WCF主机遇到BadImageFormatException

时间:2009-04-07 19:47:15

标签: c++ wcf interop iis-6 was

在引用x86 DLL时,在Vista x64上的Visual Studio 2008中创建WCF服务库很麻烦。调用32位DLL的服务需要具有x86的平台目标才能在64位操作系统上运行。执行此操作时,WcfSvcHost会在您尝试调试服务时抛出BadImageFormatException。 MS连接上有bug report。我使用的解决方法是coreflag WcfSvcHost as 32-bit

明显问题

我遇到的主要问题是第三方本机32位DLL无法使用某些WCF主机加载。当调用服务操作使用第三方DLL时,我收到以下错误:

  

System.TypeInitializationException:类型初始值设定项   “提出异常。

     

.ModuleLoadExceptionHandlerException:   之后发生了嵌套异常   导致C ++的主要异常   模块无法加载。

     

System.BadImageFormatException:模块应该包含一个   装配清单。 (例外   HRESULT:0x80131018)

NestedException:

  

句柄无效。 (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'

查看答案 from Microsoft Product Support

更新#1:控制台应用程序和WcfSvcHost.exe主机进程在同一会话和登录用户(me)下运行。我已经将WcfSvcHost.exe复制到服务目录中,手动启动并经历了相同的结果。我还检查了Windows事件日志以获取更多信息,并使用了 sxstrace ,但没有记录任何内容。

运行Process Explorer,我已经验证了以下两个进程之间的相同内容:

  • 图片:32位
  • 当前目录
  • 用户/ SID
  • 会话
  • 安全性(拒绝群组,禁用权限)

运行Process Monitor和configuring symbols,我看到WcfSvcHost会查找以下注册表和文件,而控制台主机则不会。 Process Monitor记录了大量数据,我不确定我在寻找什么:(

  

HKLM \ SOFTWARE \微软\融合\ PublisherPolicy \默认\ policy.8.0.msvcm80__b03f5f7f11d50a3a   C:\ WINDOWS \装配\ GAC_32 \ msvcm80 \ 8.0.50727.3053__b03f5f7f11d50a3a   C:\ WINDOWS \装配\ GAC_MSIL \ msvcm80 \ 8.0.50727.3053__b03f5f7f11d50a3a   C:\的Windows \组件\ GAC \ msvcm80 \ 8.0.50727.3053__b03f5f7f11d50a3a

更新#2:在IIS 6 / Windows Server 2003上托管在生产中时,会发生同样的异常。

更新#3:第三方32位.NET程序集是StreamBase API

  • sbclient.dll(托管)
  • monitor.netmodule(托管)
  • dotnetapi.dll(非托管)
  • pthreads-vc8.dll(非托管)

更新#4:添加了清单但没有成功:

  1. 已验证dotnetapi.dll和pthreads-vc8.dll具有RT_MANIFEST。 sbclient.dll .NET程序集没有清单
  2. 从GAC中删除了sbclient.dll
  3. 注册sbclient.dll以进行验证跳过
  4. 通过mt.exe向sbclient.dll和monitor.netmodule
  5. 添加了一个清单
  6. 已添加已验证的清单,并且在测试期间(通过Visual Studio - 调试模块窗口)
  7. 加载了预期的文件
  8. 在BackgroundWorker.OnDoWork()下引发相同的BadImageFormatException,调用堆栈显示对dotnetapi.dll的调用... DefaultDomain.Initalize()。
  9. 我已经确认msvcm80.dll没有清单,我相信这是唯一没有清单的文件:)

    有趣的发现

    当我在Reflector中加载monitor.netmodule时,它会说:

      

    'monitor.netmodule'不包含   装配清单。

    即使它显示错误,Reflector仍然可以反汇编托管代码。

7 个答案:

答案 0 :(得分:4)

有点晚了,但您也可以在高级设置中将应用程序池设置“启用32位应用程序”更改为true。

答案 1 :(得分:2)

Microsoft产品支持解决了这个问题:它是设计的。使用WcfSvcHost或IIS WCF主机时,非托管代码未加载到默认AppDomain中。

  

纯图像将使用CLR版本   C运行时库。然而   CRT不可验证,所以你不能   编译时使用CRT   / CLR:安全。有关更多信息,请参阅C.   运行时库。

http://msdn.microsoft.com/en-us/library/k8d11d4s.aspx

答案 2 :(得分:0)

我无法解释错误,只是我最初怀疑代码作为服务运行的上下文与将其放在控制台应用程序中时运行的上下文之间存在权限差异。 E_HANDLE HRESULT是我的线索。假设您以登录用户身份运行控制台应用程序,您可以尝试将服务配置为以该用户身份启动。如果它在该配置中有效,那么您可以尝试缩小所需资源在失败时不可用的范围。

我可以建议一个解决方法。如果有问题的DLL有一个奇怪的东西阻止它在托管服务中工作,你可以采用牺牲过程方法,因为它通常用于隔离经常崩溃的DLL。简而言之,您创建了一个代理程序,其唯一目的是代表您的主进程加载和调用DLL,使用命名管道或其他一些IPC方法来传递请求和结果。如果DLL崩溃,则启动代理程序的新实例。在你的情况下,它将有额外的好处,只有包装程序需要32位。

答案 3 :(得分:0)

您是否在“事件”查看器中看到任何特殊内容? 在Vista中,如果出现明显问题,您将在事件查看器中看到它的痕迹,它会告诉您使用SxsTrace

答案 4 :(得分:0)

您是否可以使用mt.exe文件自行手动向此DLL添加清单?

MSDN Article on using mt.exe

答案 5 :(得分:0)

这看起来有点愚蠢;但请确保您的服务在正确的应用程序池中运行。

答案 6 :(得分:0)

自己进入这个问题。我找到了helpful post。正如其他帖子所述,微软表示这是设计上的。基本上你需要:

  1. 找到您的WcfSvcHost.exe版本。 (对我和视觉工作室 2017:C:\ Program Files(x86)\ Microsoft Visual 工作室\ 2017 \专业\ Common7 \ IDE)

  2. 启动开发人员命令提示符

  3. 执行cmd:copy C:\SourcePath\WcfSvcHost.exe C:\DestinationPath\WcfSvcHost32.exe(目标无关紧要)

  4. cmd:corflags /32BIT+ /Force WcfSvcHost32.exe(可能需要cd到DestinationPath

  5. 在visual studio中打开WCF项目属性>调试选项卡>启动外部计划:C:\DestinationPath\WcfSvcHost32.exe

  6. 还要添加命令行参数:

    /service:MyWCFProjectName.dll /config:MyWCFProjectName.dll.config

    注意:您无需在此使用($ProjectDir)

  7. 启动应用。您现在可以单独启动WcfServiceHost.exe。

  8. 可选择转到解决方案>设置启动项目>多个启动项目>选择Wcf项目和客户项目。