我正在为现有的C#.NET程序开发一个插件。它的结构是这样的,你将自定义.dll文件放在程序根目录/插件/你的插件名称/你的插件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 /我的插件名称/ NAudio.dll中查找NAudio,而不是在Program Root / NAudio.dll中查找?
我正在使用VS Express 2013,目标框架是4.5,输出类型是类库。
修改
我找到了两种方法来完成这项工作(我不确定这两种方法的优点和缺点是什么 - 如果有人知道我会欣赏其他信息)。
使用NuGet包 Costura.Fody 。
安装NuGet包之后,我只需将所有其他引用“Copy Local”设置为“ False ”,然后将NAudio的“Copy Local”设置为“ True ”
现在,当我构建时,NAudio.dll被压缩并添加到我自己的DLL中。
使用下面列出的 AssemblyResolver 。
虽然它没有立即起作用,所以这里有一些额外的信息可以帮助任何人面对同样的问题:
我将Corey的代码发布到Helpers文件夹中。
我的入口点是Plugin.cs,类是public class Plugin : IPlugin, INotifyPropertyChanged
在那里,输入方法是public void Initialize(IPluginHost pluginHost)
,但只是放PluginResolver.Init(path)
不起作用。
主机程序使用WPF并且是线程化的,我必须使用宿主程序的调度程序帮助函数才能使其工作:DispatcherHelper.Invoke(() => Resolver.Init(path));
如前所述,我目前不确定使用哪种方法,但我很高兴能让它发挥作用。谢谢科里!
答案 0 :(得分: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.IO
,System.Reflection
,System.Linq
)
使用插件文件夹的基本路径调用Init
。当您尝试引用尚未加载的程序集时,它将搜索与附加dll
的程序集的基本名称匹配的第一个文件。例如,NAudio
程序集将匹配名为NAudio.dll
的第一个文件。然后它将加载并返回组件。
上述代码中没有对版本等进行检查,也没有优先选择当前插件的文件夹。