Uchwyt ReflectionTypeLoadException podczas składu MEF

Używam DirectoryCatalog W MEF, aby zaspokoić import w moim wniosku. Jednak czasami w katalogu są ukryte zespoły, które powodują ReflectionTypeLoadException, gdy próbuję skomponować katalog.

Wiem, że mogę go obejść używając oddzielnego katalogu lub używając filtra wyszukiwania na DirectoryCatalog, ale chcę bardziej ogólnego sposobu rozwiązania problemu. Czy mogę jakoś poradzić sobie z wyjątkiem i zezwolić na kontynuację kompozycji? A może jest inne bardziej ogólne rozwiązanie?

 22
Author: Athari, 2010-11-10

3 answers

DirectoryCatalog ma już kod do przechwytywania ReflectionTypeLoadException i ignorowania tych zestawów. Niestety, jak zgłosiłem , samo utworzenie AssemblyCatalog nie spowoduje jeszcze wywołania wyjątku, aby kod nie działał.

Wyjątek jest faktycznie wyzwalany przez pierwsze wywołanie AssemblyCatalog.Parts.

Zamiast używać DirectoryCatalog z MEF, będziesz musiał zrobić to sam:

  • skanowanie katalogu w poszukiwaniu zestawów
  • załaduj każdy zespół i utwórz AssemblyCatalog dla niego
  • invoke AssemblyCatalog.Parts.ToArray() aby wymusić wyjątek i złapać go
  • zestawiamy wszystkie dobre katalogi z AggregateCatalog
 25
Author: Wim Coenen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-23 15:27:51

Aby uchronić innych przed napisaniem własnej implementacji SafeDirectoryCatalog, oto ta, którą wymyśliłem na podstawie sugestii Wima Coenena:

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; }
    }
}
 44
Author: Dan Morphis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-09 22:34:11

Robiłem to z API, które pisałem i SafeDirectoryCatalog nie zapisywał wielu eksportów pasujących do pojedynczego importu z różnych zestawów. Debugowanie MEF odbywa się zazwyczaj za pomocą debuggera i TraceListener. Używałem już Log4Net i nie chciałem, aby ktoś musiał dodać kolejny wpis do pliku konfiguracyjnego tylko po to, aby wspierać logowanie. http://blogs.msdn.com/b/dsplaisted/archive/2010/07/13/how-to-debug-and-diagnose-mef-failures.aspx{[3]wymyśliłem:

    // 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);
        }
    }  
 2
Author: Mike Barry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-26 22:17:56