我在MEF中使用DirectoryCatalog
来满足我的应用程序中的导入。但是,当我尝试编写目录时,目录中有时会出现模糊的程序集导致ReflectionTypeLoadException
。
我知道我可以通过使用单独的目录或使用DirectoryCatalog
上的搜索过滤器来绕过它,但我想要一种更通用的方法来解决问题。有什么方法可以处理异常并允许组合继续吗?还是有另一种更通用的解决方案吗?
答案 0 :(得分:44)
为了避免其他人编写他们自己的SafeDirectoryCatalog实现,这是我根据Wim Coenen的建议提出的:
public class SafeDirectoryCatalog : ComposablePartCatalog
{
private readonly AggregateCatalog _catalog;
public SafeDirectoryCatalog(string directory)
{
var files = Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories);
_catalog = new AggregateCatalog();
foreach (var file in files)
{
try
{
var asmCat = new AssemblyCatalog(file);
//Force MEF to load the plugin and figure out if there are any exports
// good assemblies will not throw the RTLE exception and can be added to the catalog
if (asmCat.Parts.ToList().Count > 0)
_catalog.Catalogs.Add(asmCat);
}
catch (ReflectionTypeLoadException)
{
}
catch (BadImageFormatException)
{
}
}
}
public override IQueryable<ComposablePartDefinition> Parts
{
get { return _catalog.Parts; }
}
}
答案 1 :(得分:25)
DirectoryCatalog
已经有代码来捕获ReflectionTypeLoadException
并忽略这些程序集。不幸的是,正如我reported一样,仅仅创建AssemblyCatalog
将不会触发异常,因此代码不起作用。
实际上,第一次调用AssemblyCatalog.Parts
会触发异常。
您不必使用MEF的DirectoryCatalog
,而是自己动手:
AssemblyCatalog
AssemblyCatalog.Parts.ToArray()
来强制执行异常并抓住它AggregateCatalog
答案 2 :(得分:2)
我是从我正在编写的API执行此操作,而SafeDirectoryCatalog不会记录与来自不同程序集的单个导入匹配的多个导出。 MEF调试通常通过调试器和TraceListener完成。我已经使用过Log4Net,我不希望有人需要在配置文件中添加另一个条目以支持日志记录。 http://blogs.msdn.com/b/dsplaisted/archive/2010/07/13/how-to-debug-and-diagnose-mef-failures.aspx我提出了:
// I don't want people to have to add configuration information to get this logging.
// I know this brittle, but don't judge... please. It makes consuing the api so much
// easier.
private static void EnsureLog4NetListener()
{
try
{
Assembly compositionAssembly = Assembly.GetAssembly(typeof (CompositionContainer));
Type compSource = compositionAssembly.GetType("System.ComponentModel.Composition.Diagnostics.CompositionTraceSource");
PropertyInfo canWriteErrorProp = compSource.GetProperty("CanWriteError");
canWriteErrorProp.GetGetMethod().Invoke(null,
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Static, null, null,
null);
Type traceSourceTraceWriterType =
compositionAssembly.GetType(
"System.ComponentModel.Composition.Diagnostics.TraceSourceTraceWriter");
TraceSource traceSource = (TraceSource)traceSourceTraceWriterType.GetField("Source",
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Static).GetValue(null);
traceSource.Listeners.Add(new Log4NetTraceListener(logger));
}
catch (Exception e)
{
logger.Value.Error("Cannot hook MEF compisition listener. Composition errors may be swallowed.", e);
}
}