在Visual Studio扩展中包含外部.dll

时间:2015-09-27 17:59:35

标签: c# visual-studio .net-assembly

我的Visual Studio扩展使用外部库时遇到问题。目前我有自己的NuGet服务器,我在其上托管我的库,现在因为我不想要两次功能,所以我将扩展中的一些功能提取到现有的库中。

然而问题是,每当我想使用该程序集中的任何内容时,我都无法这样做,因为visual studio不包含.vsix包中的.dll。

到目前为止,我已经尝试过:

  1. 使用Assets从其包位置包含库。这会在解决方案中创建两个项目,它们的“包含在VSIX中”属性设置为true,这不起作用
  2. 包括项目然后添加BuiltProjectOutputGroup; BuiltProjectOutputGroupDependencies; GetCopyToOutputDirectoryItems; SatelliteDllsProjectOutputGroup;到参考的“VSIX中包含的其他组”属性,这不起作用
  3. 使用Assets将库包含为项目,但不起作用
  4. 所以现在我已经到了最后,因为似乎没有任何东西可以工作......

    我找到的解决方案已经建议我尝试的所有步骤,但此时

    我还发现这两个帖子与我的问题相同,但那些回复并不像我说的那样对我有用。

    this

    this

1 个答案:

答案 0 :(得分:1)

好的,我找到了一种方法,它是我在堆栈溢出时找到的两个答案的组合。

尽管它有点hacky,但我想它是唯一可行的方法。

所以我只是使用现有的ManualAssemblyResolver并根据我的需要调整它,结果如下:

public class ManualAssemblyResolver : IDisposable
{
    #region Attributes

    /// <summary>
    /// list of the known assemblies by this resolver
    /// </summary>
    private readonly List<Assembly> _assemblies;

    #endregion

    #region Properties

    /// <summary>
    /// function to be called when an unknown assembly is requested that is not yet kown
    /// </summary>
    public Func<ResolveEventArgs, Assembly> OnUnknowAssemblyRequested { get; set; }

    #endregion

    #region Constructor

    public ManualAssemblyResolver(params Assembly[] assemblies)
    {
        _assemblies = new List<Assembly>();

        if (assemblies != null)
            _assemblies.AddRange(assemblies);

        AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
    }

    #endregion

    #region Implement IDisposeable

    public void Dispose()
    {
        AppDomain.CurrentDomain.AssemblyResolve -= OnAssemblyResolve;
    }

    #endregion

    #region Private

    /// <summary>
    /// will be called when an unknown assembly should be resolved
    /// </summary>
    /// <param name="sender">sender of the event</param>
    /// <param name="args">event that has been sent</param>
    /// <returns>the assembly that is needed or null</returns>
    private Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)
    {
        foreach (Assembly assembly in _assemblies)
            if (args.Name == assembly.FullName)
                return assembly;

        if (OnUnknowAssemblyRequested != null)
        {
            Assembly assembly = OnUnknowAssemblyRequested(args);

            if (assembly != null)
                _assemblies.Add(assembly);

            return assembly;
        }

        return null;
    }

    #endregion
}

之后我使用Addition ExtensionManager来获取扩展的安装路径。看起来像这样

public class ExtensionManager : Singleton<ExtensionManager>
{
    #region Constructor

    /// <summary>
    /// private constructor to satisfy the singleton base class
    /// </summary>
    private ExtensionManager()
    {
        ExtensionHomePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), Definitions.Constants.FolderName);

        if (!Directory.Exists(ExtensionHomePath))
            Directory.CreateDirectory(ExtensionHomePath);

        SettingsFileFullname = Path.Combine(ExtensionHomePath, Definitions.Constants.SettingsFileName);

        InstallationPath = Path.GetDirectoryName(GetType().Assembly.Location);
    }

    #endregion

    #region Properties

    /// <summary>
    /// returns the installationPath
    /// </summary>
    public string InstallationPath { get; private set; }

    /// <summary>
    /// the path to the directory where the settings file is located as well as the log file
    /// </summary>
    public string ExtensionHomePath { get; private set; }

    /// <summary>
    /// the fullpath to the settingsfile
    /// </summary>
    public string SettingsFileFullname { get; private set; }

    #endregion
}

然后在Package的Initialize()方法中,您需要创建ManualAssemblyResolver的实例,并提供所需程序集的路径,如下所示:

    #region Attributes

    private ManualAssemblyResolver _resolver;

    #endregion

    #region Override Microsoft.VisualStudio.Shell.Package

    /// <summary>
    /// Initialization of the package; this method is called right after the package is sited, so this is the place
    /// where you can put all the initialization code that rely on services provided by VisualStudio.
    /// </summary>
    protected override void Initialize()
    {
        _resolver = new ManualAssemblyResolver(
        Assembly.LoadFrom(Path.Combine(ExtensionManager.Instance.InstallationPath, Definitions.Constants.NameOfAssemblyA)),
        Assembly.LoadFrom(Path.Combine(ExtensionManager.Instance.InstallationPath, Definitions.Constants.NameOfAssemblyB))
        );

请注意,您需要在anythingelse之前调用它,甚至触及引用程序集中的任何内容,否则将抛出FileNotFoundException。

在任何情况下,这似乎对我有用,但我希望有一个更清洁的方法来做到这一点。因此,如果任何人有更好的方法(实际上包含和从.vsix包中提取程序集的方式),请发表答案。

编辑: 好吧,现在我找到了真正的问题,这就是dll是卫星dll(它们的汇编文化设置好了)所以它们不可见......

然而,当他们仍然是satillite dlls时,上述修复工作正常。