VSIX - Cannot load file or assembly of a reference

2019-01-17 04:33发布

问题:

My question is very similar to this one, only that the answer and work-around are not working for me. Also I am in Visual Studio 2012.

I have a VSPackage which is referencing another project, which is dependent on other dlls. Everytime time I run my package in debug I get an exception that the other dlls cannot be found. They are in the output directory, and they are signed.

I tried referencing them directly by the VSPackage project to no avail.

Thoughts?

回答1:

This problem exists because Visual Studio is not looking for assemblies in a folder of your extension if your extension has no explicit dependence on these assemblies. For example, dependences set in a configuration file (IoC config) or in xaml code. I know three solutions to this problem:

  1. You can deploy these assemblies in the GAC and Visual Studio will load them. This method is good if you use a third-party library that built for use in the GAC (for example, MS Enterprise Library). But VSIX Deployment Package does not allow installing assemblies in the GAC, you can use the MSI installer.

  2. For VSPackages for Visual Studio 2010/2012 you can use ProvideBindingPath attribute. The path where your extension located will be added to the paths that Visual Studio uses to find dependent assemblies. If your extension doesn't include a VSPackage, you can add this attribute to any public class (see here).

    [ProvideBindingPath] 
    public class MyVsPackage : Package 
    { /* ... */ }
    
  3. You can manually resolve assembly names. To do this, you need to subscribe to the AssemblyResolve event and you need to return required assemblies from a handler. This is the most flexible way, if you cannot use the previous methods, this is especially for you.

    In my IntelliDebugger project, I wrote a class ManualAssemblyResolver for it:

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;
    }
}

This class must be created before the first call to the problem assembly (e.g., in Package::Initialize() method)