2010-04-17 5 views
12

Wir implementieren ein Plugin-Framework für unsere Anwendung und laden Plugins mit Assembly.Loadfrom. Wir verwenden dann GetTypes() und untersuchen die Typen mit jeder Plugin-Datei für unterstützte Schnittstellen.Assembly.GetTypes() - ReflectionTypeLoadException

Ein Pfad für die Plugins wird vom Benutzer bereitgestellt und wir durchlaufen alle Dateien im Ordner, um zu sehen, ob es (das Plugin) unsere Plugin-Schnittstelle unterstützt. Wenn dies der Fall ist, erstellen wir eine Instanz, andernfalls gehen wir zur nächsten Datei über.

Wir erstellen zwei Versionen von Software aus der einen Codebasis (appA_1 und appA_2).

Das Laden der Plugins funktioniert gut, wenn die Plugins von der Anwendung geladen werden, die zur gleichen Zeit wie die Plugin-Datei erstellt wurde. Wenn wir jedoch appA_2 erstellen und auf den Plug-in-Ordner appA_1 verweisen, erhalten wir eine Ausnahme, wenn GetTypes() aufgerufen wird.

Eine Grundversion unseres Codes ist;

var pluginAssembly = Assembly.LoadFrom(FileName);  
foreach (var pluginType in pluginAssembly.GetTypes()) 
{ 

Wir erhalten eine "ReflectionTypeLoadException" Ausnahme.

Dies ist wichtig, weil wir wollen, dass unsere Anwendung die Typen eines von jedem erstellten Plugins laden kann. Gibt es etwas, das uns fehlt?

EDIT: Nachdem die Loaderexceptions Durchlaufen wir entdeckt haben, dass es eine einzelne Datei libPublic.dll ist, die eine System.IO.FileNotFoundException Ausnahme erzeugt. Das Seltsame ist, dass sich diese Datei im Anwendungsverzeichnis befindet und das Plugin auf die Projektdatei verweist.

EDIT 2: Im Ausnahmeprotokoll wir die folgenden finden "Vergleicht man die Assemblierung-Name ergab die Diskrepanz: Revisionsnummer"

+0

Was ist die Ausnahmebedingungsnachricht? Hat die Ausnahme eine innere Ausnahme? Was ist die Botschaft davon? – dtb

+0

Gibt es einen Grund, warum Sie kein vorhandenes Framework wie MEF verwenden? – dtb

+0

Sie können immer noch Probleme wie diese verursachen, wenn Sie MEF verwenden, obwohl MEF definitiv praktisch ist, um sich um die Arbeit des Grunzens zu kümmern. –

Antwort

14

Ein paar Dinge:

  • Stellen Sie sicher, Sie don‘ t haben doppelte Assemblys im Plugin-Verzeichnis (dh Assemblys, die Sie bereits in Ihrer Haupt-App aus Ihrem App-Verzeichnis geladen haben.) Wenn Sie Ihr Plugin laden, lädt es möglicherweise eine zusätzliche Kopie derselben Assembly. Dies kann zu Fun-Ausnahmen führen wie:

    Objekt (vom Typ 'MyObject') ist nicht vom Typ 'MyObject'.

  • Wenn Sie die Ausnahme sind immer, wenn ein Typ instanziieren, müssen Sie möglicherweise AppDomain.AssemblyResolve zu handhaben:

    private void App_Startup(object sender, StartupEventArgs e) 
    { 
        // Since we'll be dynamically loading assemblies at runtime, 
        // we need to add an appropriate resolution path 
        // Otherwise weird things like failing to instantiate TypeConverters will happen 
        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; 
    } 
    
    private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 
    { 
        var domain = (AppDomain) sender; 
    
        foreach (var assembly in domain.GetAssemblies()) 
        { 
         if (assembly.FullName == args.Name) 
         { 
          return assembly; 
         } 
        } 
    
        return null; 
    } 
    

Ich weiß, es ist ein bisschen seltsam, haben die CLR zu sagen, dass, Um eine Assembly aufzulösen, suchen Sie die Assembly mit dem Namen, den wir verwenden, um sie zu lösen, aber ich habe merkwürdige Dinge ohne sie gesehen. Ich könnte beispielsweise Typen aus einer Plug-in-Assembly instanziieren, aber wenn ich versuchen würde, TypeDescriptor.GetConverter zu verwenden, würde es die TypeConverter für die Klasse nicht finden, obwohl es das Converter-Attribut in der Klasse sehen könnte.


bei Ihrer Änderungen suchen, ist dies wahrscheinlich nicht das, was Ihre aktuelle Ausnahme verursacht, wenn Sie später in diese Probleme laufen können, wie Sie mit Ihrem Plugins arbeiten.

+1

Du bist großartig! Ich hatte das doppelte Montageproblem, also hat mich diese Antwort gerettet! – JoeCool

+0

Das hat mein Problem ebenfalls gelöst. Ich habe mein Plug-in geladen, das einen benutzerdefinierten UITypeEditor und TypeConverters freigab und während meine Typen geladen würden, würden die Editoren/Konverter nicht instanziieren. Außerdem befanden sich meine Plug-Ins in einem Unterverzeichnis relativ zur Anwendung, und seltsamerweise funktionierte es, wenn ich das Plug-in in dasselbe Verzeichnis wie die Host-Anwendung legte. Diese Lösung hat dazu beigetragen, dass die Plug-Ins unabhängig von ihrem Standort funktionieren. – Mike

+0

Sie sind absolut richtig. Ich habe auch eine Assembly in einer untergeordneten Anwendung geladen, die bereits in der übergeordneten Anwendung vorhanden ist. Wenn ich mit AppDomain.CurrentDomain.GetAssemblies() geladen habe, bekam ich die Assembly und löste das Loader-Problem in GetTypes(). Vielen Dank :) @Dan Dryant –

0

Sie erhalten eine Nichtübereinstimmung der Assemblyversion. Da sich Ihre Plugins auf diese libPublic.dll beziehen, müssen Sie sie sorgfältig versionieren und insbesondere nicht ihre Revision/Build/etc. Zahlen bei jedem Kompilieren.

2

Dank dieser Post konnte ich die ReflectionTypeLoadException lösen, die ich in einem UITypeEditor bekommen habe. Es ist eine Designer-Assembly (ein winforms-Smart-Tag, das zur Entwurfszeit verwendet wird) einer benutzerdefinierten Klassenbibliothek, die nach bestimmten Typen sucht.

/// <summary> 
/// Get the types defined in the RootComponent. 
/// </summary> 
private List<Type> getAssemblyTypes(IServiceProvider provider) 
{ 
    var types = new List<Type>(); 
    try 
    { 
     IDesignerHost host = (IDesignerHost)provider.GetService(typeof(IDesignerHost)); 
     ITypeResolutionService resolution = (ITypeResolutionService)provider.GetService(typeof(ITypeResolutionService)); 
     AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => 
     { 
      foreach (var assembly in ((AppDomain)sender).GetAssemblies()) 
      { 
       if (assembly.FullName == args.Name) 
       { 
        return assembly; 
       } 
      } 

      return null; 
     }; 

     Type rootComponentType = resolution.GetType(host.RootComponentClassName, false); 
     types = rootComponentType.Assembly.GetTypes().ToList(); 
    } 
    catch 
    { 
    } 

    return types; 
} 
+0

Woher kommt IServiceProvider? Wie kann es erhalten werden? – Pangamma

Verwandte Themen