MEF 的 CompositionContainer.ComposeParts ——加载任何可以解析的内容,并忽略错误

问题描述 投票:0回答:3

到目前为止,我在 MEF 方面遇到的最大问题是,当我在插件加载器包装器中编写部件时,当它发现其中一个程序集存在导入解析问题时,加载会完全失败。 理想情况下,我希望 ComposeParts 表现出某种“忽略并继续”行为,因为理想的用户体验需要加载尽可能多的插件,并在特定插件加载失败时简单地记录事件。 我在任何地方的文档中都找不到有关此内容的信息。

如果您对如何解决此问题有任何其他建议,我会倾听!

.net plugins inversion-of-control mef
3个回答
10
投票

Wim 的示例具有基本思想,但我建议您不要直接拉动容器,而是像这样进行 Lazy ImportMany:

[Export]
public class MyApplication
{
   [ImportMany(typeof(IPlugin))]
   public IEnumerable<Lazy<IPlugin>> Plugins { get; set; }
}

然后您可以一一初始化插件并捕获其中的任何错误,例如:

void InitializePlugins()
{
   foreach (Lazy<IPlugin> plugin in Plugins)
   {
       try
       {
          plugin.Value.Initialize();
       }
       catch (CompositionException e)
       {
          // Handle the error accordingly
       }
   }   
}

在您第一次拉取 .Value 之前,不会创建实际的插件,如果插件在导入的构造函数或属性设置器中存在错误,则会发生错误。另请注意,如果插件出现错误,我会捕获 CompositionException,这是 .Value 调用中会出现的情况。


3
投票

您可以使用

AllowDefault
参数。如果没有可用部分可以满足导入,则在导入时将其设置为 true 将导致依赖关系为
null

public class MyComponent
{
    [Import(AllowDefault=true)]
    public IMyDependency MyDependency { get; set; }
}

要加载所有可用的插件,但忽略那些因缺少部分而无法加载的插件,

[ImportMany]
默认情况下已经执行了您想要的操作:

[Export]
public class MyApplication
{
   [ImportMany(typeof(IPlugin))]
   public IEnumerable<IPlugin> Plugins { get; set; }
}

请注意,上述技术只能消除由于缺少零件而导致的构图错误。如果一个部件及其导入实际上可用,但在调用构造函数时抛出意外异常,那么您仍然会收到异常。要忽略此类与组合无关的问题,您可以像这样直接调用容器:

IEnumerable<IPlugin> GetPluginsFromContainer(CompositionContainer container)
{
   foreach (Lazy<IPlugin> pluginExport in container.GetExports<IPlugin>())
   {
       try
       {
          yield return pluginExport.Value;
       }
       catch (Exception e)
       {
          // report failure to instantiate plugin somewhere
       }
   }   
}

0
投票

我对这个问题的解决方案是为每个插件调用

ComposeParts
并保留已完成的插件列表。单独加载所有插件后,使用列表中的所有插件创建一个新的
AggregateCatalog
并在该目录上使用 ComposeParts:

string[] pluginDirectories = Directory.GetDirectories(pluginsFolder);
List<string> workinglugins = new List<string>();

foreach (string pluginDirectory in pluginDirectories)
{
    Trace.WriteLine(String.Format("Discovering Plugins from '{0}'.", pluginDirectory));

    try
    {
        // Try loading each Plugin one by one
        DirectoryCatalog catalog = new DirectoryCatalog(pluginDirectory, "*Plugin.dll");
        CompositionContainer container = new CompositionContainer(catalog);
        container.ComposeParts(this);

        // Plugin worked
        workinglugins.Add(pluginDirectory);

    }
    catch (Exception ex)
    {
        // Plugin didn't work
        Trace.WriteLine(String.Format("Exception loading Plugin: {0}", ex.Message));
    }
}

if (workinglugins.Count > 0)
{

    // Create the catalog that will be used for the final composition
    AggregateCatalog catalog = new AggregateCatalog();

    foreach (string plugin in workinglugins)
    {
        try
        {
            catalog.Catalogs.Add(new DirectoryCatalog(plugin, "*Plugin.dll"));
        }
        catch (Exception ex)
        {
            Trace.WriteLine(String.Format("Exception loading Plugin: {0}", ex.Message));
        }
    }

    // Create the CompositionContainer with the parts in the catalog.
    try
    {
        _container = new CompositionContainer(catalog);
        _container.ComposeParts(this);
        Trace.WriteLine(String.Format("{0} plugins succesfully loaded.", _container.Catalog.Count()));
    }
    catch (Exception ex)
    {
        Trace.WriteLine(String.Format("Exception loading Plugins: {0}", ex.Message));
    }

}
else
{
    Trace.WriteLine(String.Format("No Plugins discovered."));
}
© www.soinside.com 2019 - 2024. All rights reserved.