如何在未安装MEF组件依赖项时优雅地降级?

时间:2013-11-15 09:34:44

标签: c# .net dll mef

我正在开发一个应用程序,它使用MEF插入外部设备(I / O设备,示波器,波形发生器等)的接口。大多数这些接口都需要DLL来访问设备,并且在可能的情况下,我将这些DLL打包到包含插件的项目中。

应用程序使用ImportMany加载实现插件接口的所有类。然后,用户可以选择需要哪些接口。

我有一个界面给我带来了困难。我无法识别所有依赖项,当我在另一个工作站上启动应用程序时,我得到一个未解决的依赖项错误。我确信当我安装所有驱动程序并支持DLL时,它会正常工作。

但是,并非所有用户都需要使用此特定接口,我不想在所有工作站上安装所有驱动程序。我正在寻找一种在无法加载某些MEF插件时优雅降级的方法。日志消息足以指出无法加载接口。只有那些试图使用接口函数的人才会收到错误。

这是我的加载程序代码:

try
{
    var catalog = new AggregateCatalog();
    var container = new CompositionContainer(catalog);
    var batch = new CompositionBatch();
    batch.AddPart(this);
    catalog.Catalogs.Add(new AssemblyCatalog(typeof (Pruef.Net.TgtManager.TargetManager).Assembly));
    container.Compose(batch);

    _targets = _targets.OrderBy(t => t.DisplayName);
}
catch (Exception x)
{
    log.Error(x);
}

2 个答案:

答案 0 :(得分:2)

尝试使用Import属性的AllowDefault属性。

[Import(AllowDefault=true)]

来自文档:

  

获取或设置一个值,该值指示属性,字段还是   导出时,参数将设置为其类型的默认值   合同名称不在容器中。

注意:如果在创建时插入throws和exception,则应用程序仍将失败。仍应处理导致丢失驱动程序的异常。

答案 1 :(得分:1)

这是我为避免错误所做的。感谢@Gusdor指出我正确的方向。延迟加载似乎是要走的路。

public class TargetManager
{
    private static log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    [ImportMany(typeof(Pruef.Net.Contracts.ITarget))]
    private IEnumerable<Lazy<Pruef.Net.Contracts.ITarget>> _targets;

    public IEnumerable<Pruef.Net.Contracts.ITarget> AvailableTargets
    {
        get;
        private set;
    }

    /// <summary>
    /// Load all known target definitions
    /// </summary>
    public void Init()
    {
        try
        {
            var catalog = new AggregateCatalog();
            var container = new CompositionContainer(catalog);
            var batch = new CompositionBatch();
            batch.AddPart(this);
            catalog.Catalogs.Add(new AssemblyCatalog(typeof(Pruef.Net.TgtManager.TargetManager).Assembly));
            container.Compose(batch);

            List<ITarget> result = new List<ITarget>();
            foreach (Lazy<ITarget> t in _targets)
            {
                try
                {
                    result.Add(t.Value);
                }
                catch (Exception x)
                {
                    // could not load plugin
                    // log error and continue
                    log.Error(x);
                }
            }
            result = result.OrderBy(t => t.DisplayName).ToList();
            AvailableTargets = result;
        }
        catch (Exception x)
        {
            log.Error(x);
        }
    }
}

}