C# MEF未检测插件依赖项

C# MEF未检测插件依赖项,c#,.net,plugins,mef,C#,.net,Plugins,Mef,我对MEF和使用插件文件夹有问题 我有一个通过MEF支持插件的主应用程序。主应用程序不引用包含.NET任务类型的程序集进行多线程处理,但有一个或多个插件引用 插件位于插件文件夹中,我使用的是DirectoryCatalog 我不断收到MEF在上抛出的ReflectionTypeLoadException 无法加载一个或多个请求的类型。取回 有关详细信息,请参阅LoaderExceptions属性 LoaderExceptions属性包含一个FileNotFoundException “无法加载文

我对MEF和使用插件文件夹有问题

我有一个通过MEF支持插件的主应用程序。主应用程序不引用包含.NET任务类型的程序集进行多线程处理,但有一个或多个插件引用

插件位于插件文件夹中,我使用的是DirectoryCatalog

我不断收到MEF在上抛出的
ReflectionTypeLoadException

无法加载一个或多个请求的类型。取回 有关详细信息,请参阅LoaderExceptions属性

LoaderExceptions属性包含一个
FileNotFoundException

“无法加载文件或程序集的System.Threading.Tasks, 版本=1.5.11.0,区域性=中性,PublicKeyToken=b03f5f7f11d50a3a'或 它的一个依赖项。系统找不到该文件 已指定。“:”System.Threading.Tasks,版本=1.5.11.0, 区域性=中性,PublicKeyToken=b03f5f7f11d50a3a“

该插件通过Microsoft NuGet软件包引用了
System.Threading.Tasks

这是我的助手方法:

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;
}
为什么即使插件文件夹中存在Microsoft.Threading.Tasks.dll和相关程序集文件,但主应用程序bin文件夹中不存在,MEF也无法加载插件?有没有办法告诉MEF在Plugins文件夹中搜索程序集依赖项


拥有插件模型意味着我无法预测插件可能引用的程序集,因此我无法将它们包含在应用程序的主bin文件夹中,这就是为什么我希望所有相关插件和插件依赖项都位于plugins文件夹中。

在支持第三方插件时,您遇到了一个基本问题。您的问题是,当您加载插件时,运行时只会在AppDomain已知的指定文件夹中搜索其引用。那将是最好的选择

实际上,您正在加载一个插件,该插件需要
System.Threading.Tasks
。该DLL位于您的
/Plugin
文件夹中。当.net加载您的插件时,它将搜索该程序集,但无法找到它,因为它位于
/plugin
文件夹中,并且失败

有几种解决方案

  • 不要使用插件文件夹
  • 这将是最简单的解决方案,当所有程序集(包括第三方库的引用)都位于您的WorkingDirectory中时,.net将很容易找到该插件的所有引用

  • 将插件文件夹添加到探测路径
  • 这将扩展路径。net将搜索第三方引用:

  • 为每个插件使用AppDomains
  • AppDomain是我选择的go here,因为它不仅允许您将程序集加载到它自己的容器中,而且还可以模拟插件的工作目录。如果插件使用与应用程序相同的框架,但使用不同的版本(例如),那么这会很方便

  • 自己加载依赖项
  • 这将是解决这个问题的“直接”方法。您可以作为加载每个程序集,确定所有依赖项,然后加载这些依赖项。那几乎可以让加兰蒂工作了

    4.1。AssemblyResolve事件

    这只是如何“重定向”.net以从PluginFolder加载程序集的另一种方法

    编辑: AssemblyCatalog也存在一定的问题,它使用
    Assembly.Load
    而不是
    Assembly.LoadFrom
    来加载给定的程序集。这是问题的一个基本部分,因为
    LoadFrom
    将探测程序集从何处生成的路径以及
    Load
    没有的依赖项

    您可以使用这样一个目录,它使用的是LoadFrom。
    免责声明:我是该项目的创建者。

    您解决了这个问题吗?我还对正确方向的解决方案或提示感兴趣,因为我目前面临着一个非常类似的问题。我不记得为什么(我的意思是可能是因为这个原因)但在我的代码中,我总是将我的
    bin
    文件夹添加为
    DirectoryCatalog
    的文件夹之一。这并没有必要指出问题所在,但您尝试过吗?
    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
        }
    }