5

引用 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”

请参阅Microsoft 产品支持的回答

更新 #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:添加清单但未成功:

  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. 添加了经过验证的清单,并且在测试期间加载了预期的文件(通过 Visual Studio - 调试模块窗口)
  6. 在 BackgroundWorker.OnDoWork() 下会抛出相同的 BadImageFormatException,调用堆栈显示对 dotnetapi.dll...DefaultDomain.Initalize() 的调用。

我已经验证 msvcm80.dll 没有清单,我相信这是加载的唯一没有清单的文件:)

有趣的发现

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

“monitor.netmodule”不包含程序集清单。

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

4

7 回答 7

3

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

于 2010-12-01T18:06:38.183 回答
2

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

纯映像将使用 C 运行时库的 CLR 版本。但是,CRT 是不可验证的,因此在使用 /clr:safe 进行编译时不能使用 CRT。有关详细信息,请参阅 C 运行时库。

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

于 2009-06-03T00:34:09.110 回答
0

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

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

于 2009-04-15T13:39:49.790 回答
0

您在事件查看器中看到什么特别的东西吗?
在 Vista 中,如果存在明显问题,您将在事件查看器中看到它的痕迹,它会告诉您使用SxsTrace

于 2009-04-15T20:00:28.613 回答
0

您能否使用 mt.exe 文件自己手动将清单添加到此 DLL 中?

关于使用 mt.exe 的 MSDN 文章

于 2009-04-18T23:49:38.753 回答
0

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

于 2012-05-18T15:22:39.687 回答
0

我自己遇到了这个问题。我找到了一个有用的帖子。正如其他帖子中所述,微软表示这是设计使然。基本上你需要:

  1. 找到您的 WcfSvcHost.exe 版本。(对于我和 Visual Studio 2017:C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\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 项目和客户端项目。

于 2018-04-20T14:13:09.567 回答