我正在开发一个应用程序,它使用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);
}
答案 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);
}
}
}
}