【问题标题】:c# Class Library Project - Load DLL from same folder?c# 类库项目 - 从同一文件夹加载 DLL?
【发布时间】:2013-12-16 23:06:16
【问题描述】:

我正在为现有的 C# .NET 程序开发插件。它的结构方式是您将自定义 .dll 文件放在 Program Root/Plugins/your plugin name/your plugin name.dll 中

这一切都很好,但现在我正在尝试在我的项目中使用 NAudio。

我已经通过 Nuget 下载了 NAudio,这部分工作正常,但问题是它在程序根目录中查找 NAudio.dll,而不是在我的插件文件夹中。

这使得我的插件很难分发,因为除了将插件放入“插件”文件夹之外,它还依赖于用户将 NAudio.dll 放到他们的程序根目录中。

来源: SettingsView.xaml:

<Button HorizontalAlignment="Center"
    Margin="0 5"
    Width="120"
    Command="{Binding SoundTestCommand,
    Source={StaticResource SettingsViewModel}}"
    Content="Sound Test" />

SettingsViewModel.cs:

using NAudio.Wave;
.
.
.
    public void SoundTest()
    {
        IWavePlayer waveOutDevice;
        WaveStream mainOutputStream;
        WaveChannel32 inputStream;

        waveOutDevice = new WaveOut();

        mainOutputStream = new Mp3FileReader(@"E:\1.mp3");
        inputStream = new WaveChannel32(mainOutputStream);

        inputStream.Volume = 0.2F;

        waveOutDevice.Init(mainOutputStream);
        waveOutDevice.Play();
    }

如何让 C# 在 Program Root/Plugins/my plugin name/NAudio.dll 中查找 NAudio,而不是在 Program Root/NAudio.dll 中查找?

我使用的是 VS Express 2013,目标框架是 4.5,输出类型是类库。

编辑:

我找到了 2 种方法来完成这项工作(我不确定这两种方法的优缺点是什么 - 如果有人知道我会很感激更多信息)。

  1. 使用 NuGet 包Costura.Fody

    安装 NuGet 包后,我只需将所有其他引用“Copy Local”设置为“False”,然后将 NAudio 的“Copy Local”设置为“True >”。

    现在,当我构建时,NAudio.dll 被压缩并添加到我自己的 DLL 中。

  2. 使用下面概述的 AssemblyResolver

    但它并没有立即起作用,所以这里有一些额外的信息可以帮助任何面临同样问题的人:

    我将 Corey 发布的代码放入 Helpers 文件夹。

    我的入口点是Plugin.cs,类是public class Plugin : IPlugin, INotifyPropertyChanged

    在那里,输入方法是public void Initialize(IPluginHost pluginHost),但简单地输入PluginResolver.Init(path)是行不通的。

    宿主程序使用 WPF 并且是线程化的,我必须使用宿主程序的调度程序辅助函数才能使其工作:DispatcherHelper.Invoke(() =&gt; Resolver.Init(path));

如前所述,我目前不确定使用哪种方法,但我很高兴我能用它。谢谢科里!

【问题讨论】:

  • @DanielHäfele 不是重复的。链接的处理应用程序,而这是特定于类库的,它不能有 app.config。这使得在我的情况下无法使用已接受的答案。 :( 我曾尝试使用 AssemblyResolve 事件,但由于未找到命名空间,我最终无法编译。
  • @Bio2hazard 实际上丹尼尔链接到的答案是完全正确的。不是公认的答案,而是建议添加 AssemblyResolve 处理程序的答案。看我的回答。

标签: c# .net dll using naudio


【解决方案1】:

您可以使用PATH 环境变量将其他文件夹添加到搜索路径。这适用于本机 DLL,但我没有尝试将其用于 .NET 程序集。

另一种选择是向当前应用程序域上的AssemblyResolve 事件添加一个挂钩,并使用自定义解析器从您找到的任何地方加载适当的程序集。这可以在程序集级别完成 - 我在 NAudio.Lame 中使用它从资源加载程序集。

类似的东西:

public static class PluginResolver
{
    private static bool hooked = false;
    public static string PluginBasePath { get; private set; }

    public static void Init(string BasePath)
    {
        PluginBasePath = BasePath;
        if (!hooked)
        {
            AppDomain.CurrentDomain.AssemblyResolve += ResolvePluginAssembly;
            hooked = true;
        }
    }

    static Assembly ResolvePluginAssembly(object sender, ResolveEventArgs args)
    {
        var asmName = new AssemblyName(args.Name).Name + ".dll";
        var assemblyFiles = Directory.EnumerateFiles(PluginBasePath, "*.dll", SearchOption.AllDirectories);

        var asmFile = assemblyFiles.FirstOrDefault(fn => string.Compare(Path.GetFileName(fn), asmName, true) == 0);

        if (string.IsNullOrEmpty(asmFile))
            return null;

        return Assembly.LoadFile(asmFile);
    }
}

(上述用途:System.IOSystem.ReflectionSystem.Linq

使用插件文件夹的基本路径调用Init。当您尝试引用尚未加载的程序集时,它将搜索与程序集的基本名称匹配并附加了dll 的第一个文件。例如,NAudio 程序集将匹配名为 NAudio.dll 的第一个文件。然后它将加载并返回程序集。

上面的代码中没有对版本等进行检查,也没有优先考虑当前插件的文件夹。

【讨论】:

  • 您好,非常感谢您的回复。我尝试了 PATH 方法,但没有成功。通过日志记录,我确认路径 env var 已正确更新,但似乎并没有尝试从那里加载 NAudio。然后,我尝试了 AssemblyResolve 选项并让它工作。 Daniel 的链接已将其放入 Main() - 我试图将其放入多个位置,但失败了。 (主机程序无法启动 - 没有日志或任何东西)感谢您的回答,我发现我可以将它放在静态辅助函数中。我确实必须调度 Init() 调用。将更新我的问题。
  • 很高兴知道PATH 选项不适用于.NET 程序集加载。
猜你喜欢
  • 2012-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多