我遇到MEF问题并使用插件文件夹。
我有一个主应用程序,通过MEF支持插件。主应用程序不引用包含.NET任务类型的程序集用于多线程,但是一个或多个插件可以。
插件位于Plugins文件夹中,我正在使用DirectoryCatalog。
我一直在{/ 1>被MEF抛出
无法加载一个或多个请求的类型。检索 LoaderExceptions属性以获取更多信息。
LoaderExceptions属性包含ReflectionTypeLoadException
“无法加载文件或程序集”System.Threading.Tasks, Version = 1.5.11.0,Culture = neutral,PublicKeyToken = b03f5f7f11d50a3a'或 其中一个依赖项。系统找不到该文件 指定。“:”System.Threading.Tasks,Version = 1.5.11.0, Culture = neutral,PublicKeyToken = b03f5f7f11d50a3a“
该插件通过Microsoft NuGet包引用引用FileNotFoundException
。
这是我的助手方法:
System.Threading.Tasks
这是我用来调用MEF并加载插件的代码。
public static void Compose(IEnumerable<string> searchFolders, params object[] parts)
{
// setup composition container
var catalog = new AggregateCatalog();
// check if folders were specified
if (searchFolders != null)
{
// add search folders
foreach (var folder in searchFolders.Where(System.IO.Directory.Exists))
{
catalog.Catalogs.Add(new DirectoryCatalog(folder, "*.dll"));
}
}
catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
// compose and create plug ins
var composer = new CompositionContainer(catalog);
composer.ComposeParts(parts);
}
public class MEFComposer
{
[ImportMany(typeof(IRepository))]
public List<IRepository> Repositories;
[ImportMany(typeof(ILogging))]
public List<ILogging> LoggingRepositories;
[ImportMany(typeof(IPlugin))]
public List<IPlugin> Plugins;
}
为什么MEF无法加载插件,即使插件文件夹中存在public void Compose()
{
// try to connect with MEF types
try
{
var parts = new MEFComposer();
MEFHelpers.Compose(new[] { Path.Combine(Application.StartupPath, "Plugins") }, parts);
RepositoryFactory.Instance.Repository = parts.Repositories.FirstOrDefault();
Logging.Repositories.AddRange(parts.LoggingRepositories);
foreach (var plugin in parts.Plugins)
{
this.applicationApi.Plugins.Add(plugin);
plugin.Connect(this.applicationApi);
}
}
catch
{
// ERR: handle error
}
}
及相关的汇编文件,但主应用程序bin文件夹中没有?有没有办法告诉MEF在Plugins文件夹中搜索程序集依赖项?
拥有插件模型意味着我无法预测插件可能引用的程序集,因此我无法将它们包含在应用程序的主bin文件夹中,这就是为什么我希望所有相关的插件和插件依赖项都在插件中文件夹中。
答案 0 :(得分:0)
在支持第三方插件时,您遇到了一个基本问题。您的问题是,在加载插件时,运行时仅在需要时在AppDomain已知的指定文件夹中搜索其引用。那就是WorkingDirectory of that process, then path etc。
本质上,您正在加载需要System.Threading.Tasks
的插件。该DLL位于您的/Plugin
文件夹中。当.net加载您的插件时,它将搜索该程序集,但由于找不到它,因为它位于/Plugin
文件夹中并且失败。
有两种解决方案。
这是最简单的解决方案,当所有程序集(包括第3方lib的引用)都位于您的WorkingDirectory中时,.net便可以轻松找到该插件的所有引用。
这将扩展路径。.net将搜索第三方引用: https://docs.microsoft.com/en-us/dotnet/framework/deployment/how-the-runtime-locates-assemblies#locating-the-assembly-through-probing
我可以选择AppDomain,因为它不仅使您可以将程序集加载到其“自己的”容器中,而且可以模拟仅插件的Working目录。如果其中一个插件使用与您的应用程序相同的框架,但使用不同的版本,则可以很方便。
那将是解决此问题的“直截了当”的方法。您可以将每个程序集加载为ReflectionOnly,确定所有依赖项,然后加载它们。那几乎会使Garantie正常工作。
4.1。 AssemblyResolve事件
这是如何“重定向” .net以从PluginFolder加载程序集的另一种方法 https://docs.microsoft.com/en-us/dotnet/api/system.appdomain.assemblyresolve?view=netframework-4.8
编辑:
AssemblyCatalog也存在一定问题,它使用Assembly.Load
而不是Assembly.LoadFrom
来加载给定的程序集。这是您问题的重要组成部分,因为LoadFrom
会针对程序集所源自的路径来探查Load
所没有的依赖关系。
https://github.com/JPVenson/MSEF/blob/master/JPB.Shell/JPB.Shell.MEF/Model/StrongNameCatalog.cs
您可以使用类似的目录,而使用LoadFrom。 免责声明:我是该项目的创建者。