在ASP.NET中使用C++/CLI组件时出现“找不到模块”错误

10
我需要在我的ASP.NET项目中包含一个(托管的)C++/CLI组件,该组件引用了其他一些(非托管的)C++ DLL。这应该没有问题——编译项目时,.NET 3.5很开心,一切似乎很好。C++/CLI组件和其他C++ DLL由另一个部门在Visual Studio 2005中以“任何CPU”为Release版本编译。VC++ 2005 Redistributable软件包已安装。当我在普通的.NET控制台应用程序中运行它时,相同的代码也可以无问题地工作。

现在,虽然这段代码在控制台应用程序中可以工作,但在ASP.NET中却没有正确地托管——它会在初始页面加载时出现错误(甚至在进入Global.asax之前)。为了测试和调试,我使用了两个机器配置:

Local Dev PC:Windows XP,32位,VC++ 2005 Redist包,Visual Studio 2010,ASP.NET 3.5,编译“Any CPU”,托管在Web开发服务器(Cassini)
Test Server(目标机器):Windows 7,64位,VC++ 2005 Redist包,托管在IIS 7中,AppPool设置为“启用32位应用程序”
在两台计算机上,当我启动ASP.NET应用程序时,都会出现以下相同的错误:
Exception Details: System.IO.FileNotFoundException: The specified module could not be found. (Exception from HRESULT: 0x8007007E)

Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:
[FileNotFoundException: The specified module could not be found. (Exception from HRESULT: 0x8007007E)]
 System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection) +0
 System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection) +43
 System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) +127
 System.Reflection.Assembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) +142
 System.Reflection.Assembly.Load(String assemblyString) +28
 System.Web.Configuration.CompilationSection.LoadAssemblyHelper(String assemblyName, Boolean starDirective) +46

[ConfigurationErrorsException: The specified module could not be found. (Exception from HRESULT: 0x8007007E)]
 System.Web.Configuration.CompilationSection.LoadAssemblyHelper(String assemblyName, Boolean starDirective) +613
 System.Web.Configuration.CompilationSection.LoadAllAssembliesFromAppDomainBinDirectory() +203
 System.Web.Configuration.CompilationSection.LoadAssembly(AssemblyInfo ai) +105
 System.Web.Compilation.BuildManager.GetReferencedAssemblies(CompilationSection compConfig) +178
 System.Web.Compilation.WebDirectoryBatchCompiler..ctor(VirtualDirectory vdir) +163
 System.Web.Compilation.BuildManager.BatchCompileWebDirectoryInternal(VirtualDirectory vdir, Boolean ignoreErrors) +53
 System.Web.Compilation.BuildManager.BatchCompileWebDirectory(VirtualDirectory vdir, VirtualPath virtualDir, Boolean ignoreErrors) +175
 System.Web.Compilation.BuildManager.CompileWebFile(VirtualPath virtualPath) +86
 System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile) +261
 System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile) +101
 System.Web.Compilation.BuildManager.GetVirtualPathObjectFactory(VirtualPath virtualPath, HttpContext context, Boolean allowCrossApp, Boolean noAssert) +126
 System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath(VirtualPath virtualPath, Type requiredBaseType, HttpContext context, Boolean allowCrossApp, Boolean noAssert) +62
 System.Web.UI.PageHandlerFactory.GetHandlerHelper(HttpContext context, String requestType, VirtualPath virtualPath, String physicalPath) +33
 System.Web.UI.PageHandlerFactory.System.Web.IHttpHandlerFactory2.GetHandler(HttpContext context, String requestType, VirtualPath virtualPath, String physicalPath) +40
 System.Web.HttpApplication.MapHttpHandler(HttpContext context, String requestType, VirtualPath path, String pathTranslated, Boolean useAppConfig) +160
 System.Web.MapHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +93
 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

现在很奇怪……它没有说明缺少哪个汇编,即使Fuslogvw.exe或sxstrace.exe也没有记录任何内容。当然,这个错误似乎取决于C++/CLI汇编或非托管C++ DLL。如果我从ASP.NET项目和代码中删除了C++/CLI汇编引用,它就可以正常工作。现在因为C++/CLI汇编依赖于未在ASP.NET项目中引用的本机C++ DLL,所以我将所有依赖的C++ DLL复制到ASP.NET项目输出文件夹的“bin”文件夹中(与工作的控制台应用程序相同)。虽然每个C++东西都已经以Release模式编译,并安装了正确的VC++ Redist包,但应该有所有依赖项。当然,我知道有一个FileNotFoundException,但我无法找出缺少什么……

如上所述:访问C++/CLI组件的相同代码在两台测试PC上的.NET 3.5控制台应用程序中均可正常工作(我已部署相同的依赖项),并将相关的C++ DLL部署到输出文件夹中,只是在ASP.NET中我会得到上述错误。

您有什么建议可以摆脱这个问题,或者如何进一步追踪它呢?

(当然我在StackOverflow和Google上搜索过这个问题,例如我找到了以下链接,但它们没有帮助:
- "运行C# ASP.NET Web服务引用C++ dll时出现“指定的模块无法找到”错误
- 从x64 .NET访问x86 COM
- 在32位环境中开发的ASP.NET应用程序在64位环境中无法工作
- 来自Windows Server 2008 R2的.NET 2.0 Web服务的模块未找到异常

2个回答

5

ProcMon救了我。

路径也是我的问题。看来IIS在C:\Windows\System32\inetsrv文件夹中为每个托管dll创建了一个阴影副本。但对于非托管代码,情况并非如此。当它要加载非托管dll时,它会搜索环境路径而不是IIS中应用程序的bin目录。

非常感谢Aristos!


但是你是怎么解决这个问题的?将bin文件夹添加到PATH了吗? - CrazyMORF

4

您的代码到达了_nLoad,这很好,因为已经通过了所有加载检查并移动到核心以实际加载dll,但它失败了。

首先从http://www.dependencywalker.com/下载Dependency Walker并在dll上使用它查找此dll运行所需的其他资源。我怀疑无法加载其他一些dll文件。

此外,可能这个dll正在搜索其他找不到的文件,因此不能加载。第二种方法是使用sysinternals的File MonitorProcess Monitor查找失败的内容。

http://technet.microsoft.com/en-us/sysinternals
http://technet.microsoft.com/en-us/sysinternals/bb896645


@Matthias,我写代码时可能因为无法加载某些资源文件而出现问题。使用文件监视器找出它们。 - Aristos
@Matthias,也许在你运行的账户路径上,但不在运行asp.net的池账户路径上!请在运行池的账户上进行修复。 - Aristos
@Matthias 登录,使用池账户,或者只需从Windows工具中更改池账户的设置。 - Aristos
我只是想知道为什么它在搜索路径时,不自动搜索ASP.NET应用程序的bin部署文件夹和C:\Windows\winsxs文件夹(用于核心VC++ DLL)?我不想在部署时更改PATH变量来使其工作。此外,这种方法容易出错,因为部署目标可能会发生变化。我只想知道是否有可能在没有PATH的情况下使其工作。 - Matthias
@Matthias 这些错误需要花费太多时间来追踪先加载什么,后加载什么等等。也可以尝试使用文件监视器,它只关注文件并且速度更快。 - Aristos
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接