2010-11-10 18 views
22

我在MEF中使用了DirectoryCatalog以滿足我的應用程序中的導入。但是,當我嘗試編寫目錄時,目錄中有時會導致ReflectionTypeLoadException混淆的程序集。在MEF合成過程中處理ReflectionTypeLoadException

我知道我可以通過使用一個單獨的目錄或使用DirectoryCatalog上的搜索過濾器來獲得它,但我想要一個更通用的方法來解決問題。有什麼方法可以處理異常並允許組合繼續?還是有另一種更一般的解決方案?

回答

25

DirectoryCatalog已經有代碼來捕獲ReflectionTypeLoadException並忽略這些程序集。不幸的是,因爲我有reported,只是創建AssemblyCatalog不會觸發異常,以便代碼不起作用。

該例外實際上是由第一次致電AssemblyCatalog.Parts觸發的。

而不是使用MEF的DirectoryCatalog的,你必須做你自己:

  • 掃描組件目錄
  • 負荷每個裝配,並創建一個AssemblyCatalog
  • 調用AssemblyCatalog.Parts.ToArray()給力例外,並捕獲它
  • 聚合所有好的目錄與一個AggregateCatalog
+1

非常好!謝謝。 我創建了一個從AggregateCatalog派生的SafeDirectoryCatalog,並使用它一次加載一個文件,只有在它不窒礙訪問部件時纔將其添加到Catalogs集合。 作品一種享受! – 2010-11-10 17:40:32

+1

@PhilJPearson:我已經更新了.NET 4.5的答案。顯然調用'.Parts'已經不夠了,你現在必須用'.Parts.ToArray()'強制枚舉。 – 2012-08-23 15:31:35

+2

所以他們沒有修正4.5中的錯誤 - 他們實際上已經讓它變得更糟! – 2012-08-23 20:50:24

43

爲了救別人通過自己編寫的實施SafeDirectoryCatalog的,這裏是我想出了基於維姆·科嫩的建議之一:

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; } 
    } 
} 
+6

+1,但我會在catch語句中添加一些日誌記錄。您可能還想捕獲「BadImageFormatException」來忽略非.NET DLL。 – 2011-04-13 09:08:06

+0

Directory.EnumerateFiles應該是Directory.GetFiles – 2011-04-20 08:37:22

+4

Steve,Directory.EnumerateFiles是.NET 4中的新功能,並且具有性能優勢,因爲條目會在您請求時返回,而不是一次全部處理。GetFiles – 2011-04-22 06:27:52

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); 
     } 
    } 
+0

任何示例完整代碼?謝謝 – Kiquenet 2012-03-13 09:34:04