我正在开发一个项目,作为多个插件的框架,这些插件应该在运行时加载。
我的任务是在应用程序文件夹中有以下结构:
- 两个目录及其子目录。一个命名为“/addons”用于插件,另一个命名为“/ref”用于任何这些插件可能使用的其他引用(如
System.Windows.Interactivity.dll
)。 - 从应用程序菜单中选择其中一个插件后,应在运行时加载.dll并打开预设入口点。
- 新加载的程序集的所有引用也应该被加载。
我知道加载插件时的子文件夹和文件名,因此我只需使用Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location))
和Path.Combine()
来构建到.dll的路径,然后使用Assembly.LoadFile()
进行加载,接着使用反射与assembly.GetExportedTypes()
查找继承自我的'EntryPointBase'类的类,最后使用Activator.CreateInstance()
创建它。
但是,一旦我在我的Add-On中有任何引用,在assembly.GetExportedTypes()
处将弹出一个System.IO.FileNotFoundException
。
我编写了一个方法来加载所有引用的程序集,甚至使它递归加载所有引用的引用,如下所示:
public void LoadReferences(Assembly assembly)
{
var loadedReferences = AppDomain.CurrentDomain.GetAssemblies();
foreach (AssemblyName reference in assembly.GetReferencedAssemblies())
{
//only load when the reference has not already been loaded
if (loadedReferences.FirstOrDefault(a => a.FullName == reference.FullName) == null)
{
//search in all subfolders
foreach (var location in Directory.GetDirectories(Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location)))
{
//GetDirectoriesRecusrive searchs all subfolders and their subfolders recursive and
//returns a list of paths for all files found
foreach (var dir in GetDirectoriesRecusrive(location))
{
var assemblyPath = Directory.GetFiles(dir, "*.dll").FirstOrDefault(f => Path.GetFileName(f) == reference.Name+".dll");
if (assemblyPath != null)
{
Assembly.LoadFile(assemblyPath);
break; //as soon as you find a vald .dll, stop the search for this reference.
}
}
}
}
}
}
通过检查AppDomain.CurrentDomain.GetAssemblies()
,确保所有参考项都已加载,但异常仍然存在。
如果所有程序集都直接放在应用程序文件夹中,或者如果插件的所有引用项已经由启动应用程序本身引用,则其可以工作。这两种方式都不适合我的情况,因为领导们要求使用此文件系统,并且新引用的插件应能够在不触及应用程序本身的情况下加载。
问题:
如何从一个子文件夹中加载程序集及其引用而不出现System.IO.FileNotFoundException
错误?
附加信息:
- 应用程序采用新的.csproj格式,并在
<TargetFrameworks>netcoreapp3.1;net472</TargetFrameworks>
上运行,尽管对net472的支持很快将停止(目前仍在net472上进行调试) - 大多数插件仍采用旧的.csproj格式,在net472上运行
- ref子文件夹也是按子文件夹结构构建的(devexpress、system等),而插件子文件夹没有更多的子文件夹。
AppDomain
的AssemblyResolve
事件。 - Reza Aghaei