【问题标题】:MEF not detecting plugin dependenciesMEF 未检测到插件依赖项
【发布时间】:2015-01-17 22:00:37
【问题描述】:

我在使用 MEF 和使用插件文件夹时遇到问题。

我有一个通过 MEF 支持插件的主应用程序。主应用程序不引用包含用于多线程的 .NET Task 类型的程序集,但一个或多个插件会。

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

我不断收到 ReflectionTypeLoadException 被 MEF 抛出

无法加载一种或多种请求的类型。检索 LoaderExceptions 属性以获取更多信息。

LoaderExceptions 属性包含一个FileNotFoundException

“无法加载文件或程序集'System.Threading.Tasks, 版本=1.5.11.0,文化=中性,PublicKeyToken=b03f5f7f11d50a3a' 或 它的依赖项之一。系统找不到文件 指定。":"System.Threading.Tasks,版本=1.5.11.0, Culture=neutral, 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;
}

这是我用来调用 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
    }
}

为什么即使 Microsoft.Threading.Tasks.dll 和相关的程序集文件存在于 Plugins 文件夹中,但不是主应用程序 bin 文件夹中,MEF 也无法加载插件?有没有办法告诉 MEF 在 Plugins 文件夹中搜索程序集依赖项?

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

【问题讨论】:

  • 这个问题你解决了吗?
  • 我也对正确方向的解决方案或提示感兴趣,因为我目前面临着类似的问题。
  • 我不记得为什么(我的意思是可能是因为这个原因),但在我的代码中,我总是将我的 bin 文件夹添加为 DirectoryCatalog 的文件夹之一。这不一定指向问题,但是您尝试过吗?

标签: c# .net plugins mef


【解决方案1】:

您在支持 3rd 方插件时遇到了一个基本问题。您的问题是,当您加载插件时,运行时将在需要时仅在您的 AppDomain 知道的指定文件夹中搜索其引用。那将是WorkingDirectory of that process, then path etc

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

有几个解决方案。

  1. 不要使用插件文件夹

这将是最简单的解决方案,当所有程序集(包括第 3 方库的引用)都位于您的 WorkingDirectory 中时,.net 将轻松找到该插件的所有引用。

  1. 将插件文件夹添加到您的探测路径

这将扩展 .net 搜索第 3 方引用的路径: https://docs.microsoft.com/en-us/dotnet/framework/deployment/how-the-runtime-locates-assemblies#locating-the-assembly-through-probing

  1. 为每个插件使用 AppDomains。

AppDomain 是我在这里的选择,因为它不仅允许您将程序集加载到其“自己的”容器中,还可以仅为插件模拟工作目录。如果某个插件使用与您的应用程序相同的框架,但版本不同,这可能会派上用场。

  1. 自己加载依赖

这将是解决此问题的“直接”方法。您可以将每个程序集加载为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 的目录。 免责声明:我是该项目的创建者。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-27
    • 1970-01-01
    相关资源
    最近更新 更多