"Could not load file or assembly" 使用 COM Interop(DLL 地狱?)

"Could not load file or assembly" using COM Interop (DLL HELL?)

我正在构建一个 COM 可见对象,它需要从一个用 Sybase Powerbuilder 11.5 编写的软件中调用。 我正在使用 C# 和 .Net Framework 4.7.2。 我通常毫无问题地构建这类对象并使用 regasm /codebase 注册它们,因为这是 Powerbuilder 喜欢它们的方式。

现在我正在尝试构建一个引用这些 nuget 包的最新版本的对象:

Microsoft.Graph
Microsoft.Graph.Auth
Microsoft.IdentityModel.Clients.ActiveDirectory
Graph.Community

我的 class 库项目有一个 com 可见 class。 我构建了一个控制台应用程序,它引用该库(它不使用 COM 服务器)来测试代码,并且在我的开发机器上从命令行一切正常。 我还可以 运行 从我的目标机器上运行控制台应用程序,没有任何问题。

当我尝试 运行 使用 COM 对象的 Powerbuilder 应用程序时,它抛出错误:

Could not load file or assembly 'Microsoft.Graph.Core, Version=1.23.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies.

我在程序集的文件夹中有那个 dll,但它是 1.24.0.0 版本。 我有两个问题:

  1. 为什么控制台应用程序工作而 COM 对象不工作,因为它们使用相同的程序集?
  2. 如何解决对象的 COM 版本中的版本控制问题?

我找到了问题的解决方案,但没有完全理解。 这是一个交叉引用问题,其中包 A 和 B 都依赖于包 C,但需要不同的版本。 我不明白为什么这个错误只在使用 COM 接口而不是控制台应用程序时出现。

这是我解决的问题:

// Define the AssemblyResolve event in the constructor of the COM Object.
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

// Get the path where COM Object's dll is
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
_dllPath = System.IO.Path.GetDirectoryName(path);

Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            // Get the name of the assembly that failed loading
            var name = new AssemblyName(args.Name);

            // Manage the assembly that I know will cause problems
            string bindingAssembly = "Microsoft.Graph.Core";
            if (name.Name == bindingAssembly)
            {
                // Load the assembly from the COM Object's folder, and use whatever version there is
                return Assembly.LoadFrom(System.IO.Path.Combine(_dllPath, bindingAssembly + ".dll"));
            }

            // I should not get here. If I do I need to add another manual assembly load for the dll that failed loading
            return null;
        }