Pluginsystem mit MEF funktioniert nur auf Buildcomputer

  • C#

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von Trade.

    Pluginsystem mit MEF funktioniert nur auf Buildcomputer

    Hallo mal wieder.

    Ich habe derzeit ein sehr merkwürdiges Problem. Im Internet konnte ich nichts dazu finden und ich habe auch keine Idee, woran es liegen könnte.
    Ich habe ein Pluginsystem mit MEF realisiert. Es ist etwa so aufgebaut:

    Code der Anwednung, die die Plugins lädt:
    Spoiler anzeigen

    C#-Quellcode

    1. public static class PackageManager
    2. {
    3. [ImportMany(typeof(IPackage))]
    4. private static IPackage[] _packages;
    5. public static string PackageLocation { get; set; }
    6. public static IPackage[] Packages
    7. {
    8. get
    9. {
    10. return _packages;
    11. }
    12. }
    13. static PackageManager()
    14. {
    15. PackageLocation = @".\Packages\";
    16. }
    17. public static void LoadPackages()
    18. {
    19. if (!Directory.Exists(PackageLocation))
    20. throw new InvalidOperationException("Der angegebene Ordner existiert nicht!");
    21. if (_packages != null)
    22. DisapplyPackages();
    23. var catalog = new DirectoryCatalog(PackageLocation);
    24. var container = new CompositionContainer(catalog);
    25. _packages = container.GetExportedValues<IPackage>().ToArray();
    26. }
    27. }
    28. }
    29. public interface IPackage
    30. {
    31. string Manufacturer { get; }
    32. string PackageName { get; }
    33. IProjectTypeDescriptor[] ProjectTypeDescriptors { get; }
    34. ICodeFileTypeDescriptor[] CodeFileTypeDescriptors { get; }
    35. }

    Code des Plugins:
    Spoiler anzeigen

    C#-Quellcode

    1. [Export(typeof(IPackage))]
    2. public class CSPackage : IPackage
    3. {
    4. IProjectTypeDescriptor projDesc;
    5. ICodeFileTypeDescriptor cfDesc;
    6. public CSPackage()
    7. {
    8. //Diese Typen sind für das Problem nicht relevant
    9. projDesc = new CSProjectTypeDescriptor();
    10. cfDesc = new CSCodeFileTypeDescriptor();
    11. }
    12. public string Manufacturer
    13. {
    14. get { return "Artentus"; }
    15. }
    16. public string PackageName
    17. {
    18. get { return "C# Standardpaket"; }
    19. }
    20. public IProjectTypeDescriptor[] ProjectTypeDescriptors
    21. {
    22. get { return new[] { projDesc }; }
    23. }
    24. public ICodeFileTypeDescriptor[] CodeFileTypeDescriptors
    25. {
    26. get { return new[] { cfDesc }; }
    27. }
    28. }


    Wenn ich das auf meine Computer laufen lasse, dann funktioniert es einwandfrei, allerdings funktioniert es auf keinen anderen Computer.
    Ich habe bereits ausprobiert, dass Projekt in einer VM zu öffnen. Sobald ich es dort kompiliert habe hat es dort auch funktioniert.
    Also, hat jemand eine Idee, warum das nur auf dem Computer funktioniert, auf dem die Anwendung erstellt wurde?

    Edit:
    Ich hab jetz auch mal die Vorgänge gelogged:
    Spoiler anzeigen

    C#-Quellcode

    1. public static void LoadPackages()
    2. {
    3. if (!Directory.Exists(PackageLocation))
    4. throw new InvalidOperationException("Der angegebene Ordner existiert nicht!");
    5. if (_packages != null)
    6. DisapplyPackages();
    7. var catalog = new DirectoryCatalog(PackageLocation);
    8. var container = new CompositionContainer(catalog);
    9. _packages = container.GetExportedValues<IPackage>().ToArray();
    10. using (var sw = new StreamWriter(@".\Log.txt"))
    11. {
    12. foreach (var package in _packages)
    13. {
    14. sw.WriteLine("Package " + package.PackageName + " found");
    15. foreach (var projDesc in package.ProjectTypeDescriptors)
    16. {
    17. sw.WriteLine("\tProjectDescription: " + projDesc.TypeName);
    18. }
    19. foreach (var cfDesc in package.CodeFileTypeDescriptors)
    20. {
    21. sw.WriteLine("\tCodeFileDescription: " + cfDesc.LanguageName);
    22. }
    23. sw.WriteLine();
    24. }
    25. }
    26. }

    Auf meinem Entwicklungssytem bekomme ich die erwartete Ausgabe, in der VM entsteht aber nur eine leere Datei.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Artentus“ ()

    Liegt es an der PackageLocation?
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    Ok...
    Wenn nicht, dann schau mal, ob es noch andere benutzerdefinierte Einstellungen gibt, die evtl anders sind.
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    Ok, also der Pfad ist definitiv der richtige, muss also an was anderem liegen.

    Edit: ich konnte den Fehler weiter eingrenzen, die DLLs werden noch korrekt erkannt. Bis Zeile 9 funktioniert der Code also schon mal so, wie er soll. Komment also nur noch die Zeilen 10 und 11 in Frage.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Artentus“ ()

    Du hast da stehen: DisapplyPackages()
    Was ist wenn da irgendwas nicht enthalten ist...?
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    Du hast ja gepostet, dass es jetzt in der VM gefunzt hat. Wo lag der Fehler?
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    Das Problem ist wahrscheinlich gelöst. Es scheint so, als ob der DirectoryCatalog daran schuld wäre. Jetzt lade ich alle Plugins einzeln mit dem AssemblyCatalog, und mit diesem funktioniert es.
    Spoiler anzeigen

    C#-Quellcode

    1. public static void LoadPackages()
    2. {
    3. var dir = new DirectoryInfo(PackageLocation);
    4. if (!dir.Exists)
    5. throw new InvalidOperationException("Der angegebene Ordner existiert nicht!");
    6. if (_packages != null)
    7. DisapplyPackages();
    8. var catalogs = new List<AssemblyCatalog>();
    9. foreach (var f in dir.EnumerateFiles("*.dll"))
    10. catalogs.Add(new AssemblyCatalog(f.FullName));
    11. var catalog = new AggregateCatalog(catalogs);
    12. var container = new CompositionContainer(catalog);
    13. _packages = container.GetExportedValues<IPackage>().ToArray();
    14. }

    Wenn doch noch was in der Richtung nicht stimmt, dann melde ich mich wieder.

    @Trade
    Da warst du wohl ein ganz kleines Bisschen zu schnell. :)
    Ok alles klar. Haue mal da btw noch CreateAssemblyCatalogGuarded mit rein.
    Das fügt einen "Abfang" für Exceptions ein.

    C#-Quellcode

    1. AssemblyCatalog assemblyCatalog = null;
    2. assemblyCatalog = CreateAssemblyCatalogGuarded(file);


    Generell ginge das so. Beim Dictionary wird halt ein Dictionary<string> erstellt. Ein Dictionary wäre in den meisten Fällen eigentlich besser, aber warum es nicht geht kann ich mir auch nicht erklären.
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Trade“ ()

    Ok verstehe. War nur ein allgemeiner Tipp ;)
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!: