VSIX - 无法加载已引用 DLL 的文件或程序集

18
我的问题与这个非常相似,只是答案和解决方法对我不起作用。并且我在使用Visual Studio 2012。
我有一个VSPackage引用了另一个项目,该项目又依赖于其他dll文件。每次我在调试中运行我的包时,都会出现无法找到其他dll文件的异常。它们在输出目录中,并且已经签名。
我尝试直接从VSPackage项目中引用它们,但没有成功。
想法?
1个回答

44

这个问题存在是因为Visual Studio没有在你的扩展目录中查找程序集,如果你的扩展没有明确依赖于这些程序集。例如,在配置文件(IoC config)或xaml代码中设置的依赖关系。我知道三种解决这个问题的方法:

  1. 你可以将这些程序集部署到GAC中,Visual Studio将加载它们。如果你使用的是为在GAC中使用而构建的第三方库(例如MS Enterprise Library),那么这种方法很好。但是VSIX Deployment Package不允许在GAC中安装程序集,你可以使用MSI安装程序。

  2. 对于Visual Studio 2010/2012的VSPackages,你可以使用ProvideBindingPath属性。你的扩展所在的路径将被添加到Visual Studio用于查找依赖程序集的路径中。如果你的扩展不包含VSPackage,你可以将此属性添加到任何公共类 (参见此处)。

[ProvideBindingPath] 
public class MyVsPackage : Package 
{ /* ... */ }
  • 您可以手动解析程序集名称。要做到这一点,您需要订阅AssemblyResolve事件,并从处理程序返回所需的程序集。如果您无法使用先前的方法,则这是最灵活的方式,特别适合您。

    在我的IntelliDebugger项目中,我为此编写了一个名为ManualAssemblyResolver的类:

  • using System;
    using System.Reflection;
        
    namespace IntelliEgg.Debugger.Utility
    {
        public class ManualAssemblyResolver : IDisposable
        {
            public ManualAssemblyResolver(Assembly assembly)
            {
                if (assembly == null)
                    throw new ArgumentNullException("assembly");
    
                _assemblies = new[] {assembly};
                AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
            }
    
            public ManualAssemblyResolver(params Assembly[] assemblies)
            {
                if (assemblies == null)
                    throw new ArgumentNullException("assemblies");
    
                if (assemblies.Length == 0)
                    throw new ArgumentException("Assemblies should be not empty.", "assemblies");
    
                _assemblies = assemblies;
                AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
            }
    
            public void Dispose()
            {
                AppDomain.CurrentDomain.AssemblyResolve -= OnAssemblyResolve;
            }
    
            private Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)
            {
                foreach (Assembly assembly in _assemblies)
                {
                    if (args.Name == assembly.FullName)
                    {
                        return assembly;
                    }
                }
    
                return null;
            }
    
            private readonly Assembly[] _assemblies;
        }
    }
    

    在问题装配的第一次调用之前必须创建此类(例如,在Package::Initialize()方法中)


    你是如何加载程序集并传递到这个工具类的?更确切地说,你使用了什么上下文?是 Assembly.LoadFrom(filename) 吗?我想知道如何保护同一版本的程序集不被另一个上下文中的插件加载? - Sheldon Warkentin
    1
    是的,我使用 Assembly.LoadFrom()typeof(ClassFromMyAssembly).Assembly 以及在项目中引用 MyAssembly(用于 System.Windows.Interactivity.dll)。使用 ManualAssemblyResolver 的目的是允许 Visual Studio 从任何文件夹加载所有相关程序集,并在代码中明确确定它。为了支持模块化,我使用 MS Prism 并在 Bootstrapper 类中配置模块加载。 - Mikhail Shcherbakov
    1. 对我来说有效。如果其他扩展程序也提供了该路径并使用相同的库,是否会带来问题?
    - JoanComasFdz
    #2在VS2017中解决了我的问题。它在之前的几年里一直可以正常工作,但现在突然需要它。我不明白为什么。 - Vizu

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