2009-07-01 9 views
28

Ich versuche, ein Plugin-System zu schreiben, um einige Erweiterbarkeit zu einer Anwendung von mir zu geben, damit jemand ein Plugin für die Anwendung schreiben kann, ohne den Code der Hauptanwendung zu berühren (und das Risiko etwas zu brechen).Schreiben C# Plugin-System

Ich habe die Basis „IPlugin“ Schnittstelle geschrieben (atm, noch nichts implementiert)

Hier ist, wie ich bin Laden:

public static void Load() 
{ 
    // rawr: http://www.codeproject.com/KB/cs/c__plugin_architecture.aspx 
    String[] pluginFiles = Directory.GetFiles(Plugins.PluginsDirectory, "*.dll"); 
    foreach (var plugin in pluginFiles) 
    { 
     Type objType = null; 
     try 
     { 
      //Assembly.GetExecutingAssembly().GetName().Name 
      MessageBox.Show(Directory.GetCurrentDirectory()); 
      Assembly asm = Assembly.Load(plugin); 
      if (asm != null) 
      { 
       objType = asm.GetType(asm.FullName); 
       if (objType != null) 
       { 
        if (typeof(IPlugin).IsAssignableFrom(objType)) 
        { 
         MessageBox.Show(Directory.GetCurrentDirectory()); 
         IPlugin ipi = (IPlugin)Activator.CreateInstance(objType); 
         ipi.Host = Plugins.m_PluginsHost; 
         ipi.Assembly = asm; 
        } 
       } 
      } 
     } 
     catch (Exception e) 
     { 
      MessageBox.Show(e.ToString(), "Unhandled Exception! (Please Report!)", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information); 
     } 
    } 
} 

Ein Freund zu helfen versucht, aber ich wirklich Ich habe nicht verstanden, was falsch war.

Die Ordnerstruktur für Plugins ist die folgende:

\
\ Plugins \

Alle Plugins eine DLL namens "Lab.Core.dll" in der [root] Verzeichnis verweisen und es ist nicht im Plugins-Verzeichnis vorhanden, da doppelte Referenzen geladen werden.

Das Plugin-System wird von Lab.Core.dll geladen, die auch von meiner ausführbaren Datei referenziert wird. Geben Sie "IPlugin" in Lab.Core.dll ein. Lab.Core.dll ist, genau wie genannt, der Kern meiner Anwendung.

EDIT:

Frage: Warum/Was die Ausnahme ist, ich bin immer und wie könnte ich mich über die Festsetzung es?

FINAL EDIT:

Ok, so habe ich beschlossen, es neu zu schreiben, nachdem irgend Quellcode sucht ein Freund für einen TF2 Regler geschrieben.

Hier ist, was ich habe und es funktioniert:

public class TestPlugin : IPlugin { 
    #region Constructor 

    public TestPlugin() { 
     // 
    } 

    #endregion 

    #region IPlugin Members 

    public String Name { 
     get { 
      return "Test Plugin"; 
     } 
    } 

    public String Version { 
     get { 
      return "1.0.0"; 
     } 
    } 

    public String Author { 
     get { 
      return "Zack"; 
     } 
    } 

    public Boolean OnLoad() { 
     MessageBox.Show("Loaded!"); 
     return true; 
    } 

    public Boolean OnAllLoaded() { 
     MessageBox.Show("All loaded!"); 
     return true; 
    } 

    #endregion 
} 

     public static void Load(String file) { 
     if (!File.Exists(file) || !file.EndsWith(".dll", true, null)) 
      return; 

     Assembly asm = null; 

     try { 
      asm = Assembly.LoadFile(file); 
     } catch (Exception) { 
      // unable to load 
      return; 
     } 

     Type pluginInfo = null; 
     try { 
      Type[] types = asm.GetTypes(); 
      Assembly core = AppDomain.CurrentDomain.GetAssemblies().Single(x => x.GetName().Name.Equals("Lab.Core")); 
      Type type = core.GetType("Lab.Core.IPlugin"); 
      foreach (var t in types) 
       if (type.IsAssignableFrom((Type)t)) { 
        pluginInfo = t; 
        break; 
       } 

      if (pluginInfo != null) { 
       Object o = Activator.CreateInstance(pluginInfo); 
       IPlugin plugin = (IPlugin)o; 
       Plugins.Register(plugin); 
      } 
     } catch (Exception) { 
     } 
    } 

    public static void LoadAll() { 
     String[] files = Directory.GetFiles("./Plugins/", "*.dll"); 
     foreach (var s in files) 
      Load(Path.Combine(Environment.CurrentDirectory, s)); 

     for (Int32 i = 0; i < Plugins.List.Count; ++i) { 
      IPlugin p = Plugins.List.ElementAt(i); 
      try { 
       if (!p.OnAllLoaded()) { 
        Plugins.List.RemoveAt(i); 
        --i; 
       } 
      } catch (Exception) { 
       Plugins.List.RemoveAt(i); 
       --i; 
      } 
     } 
    } 
+2

Ich nehme zur Kenntnis, dass Sie nicht wirklich eine Frage gestellt, haben Sie gerade beschrieben, was Sie zu tun versuchen. Können Sie Ihre Frage in Form einer Frage formulieren? –

+1

Err. Entschuldigung, ich habe aufgelegt, um zu erklären, was ich mache, aber habe die Frage vergessen. : x Ich werde diesen Schnitt machen. – Zack

+1

Bitte posten Sie die vollständige Ausnahme, die Sie erhalten haben, komplett mit Stack-Trace und allen inneren Ausnahmen. Veröffentlichen Sie die Ergebnisse von ex.ToString(). –

Antwort

7

Es klingt wie Sie einen zirkulären Verweis haben. Du hast gesagt, dass deine Plugins Lab.Core.DLL referenzieren, aber du sagst auch, dass die Plugins von Lab.Core.DLL geladen wurden.

Bin ich falsch verstanden, was hier passiert?

EDIT: OK jetzt, dass Sie Ihre Frage auf die Frage hinzugefügt haben ...

Sie müssen Lab.Core.DLL zugänglich Plugin haben, da es sich um eine Abhängigkeit ist geladen. Normalerweise würde das bedeuten, es im selben Verzeichnis oder im GAC zu haben.

Ich vermute, es gibt tiefere Designprobleme hier, aber das ist Ihr unmittelbares Problem.

+0

Danke für die Hilfe. Ich habe es am Ende nach dem Sorce-Code eines Freundes neu geschrieben. Bearbeiteter Originalbeitrag, um meine Lösung zu integrieren. :) – Zack

28

Der Managed Extensibility Framework (MEF) eine neue Bibliothek in .NET ist, die größer ist die Wiederverwendung von Anwendungen und Komponenten ermöglicht. Durch die Verwendung von MEF können .NET-Anwendungen die Verschiebung von statisch zu dynamisch zusammengesetzt machen. Wenn Sie erweiterbare Anwendungen, erweiterbare Frameworks und Anwendungserweiterungen erstellen, ist MEF genau das Richtige für Sie.

http://www.codeplex.com/MEF

Edit: CodePlex weggeht - der Code für Archivierungszwecke zu Github nur verschoben wurde: https://github.com/MicrosoftArchive/mef

+4

Dies wurde in Codeplex verschoben: http://www.codeplex.com/ MEF –

+1

Dies sollte wirklich ohne die Verwendung von MEF möglich sein. –

+10

Natürlich ist es ohne den Einsatz von MEF möglich. Es gibt nichts Magisches in MEF. Aber MEF wurde von Experten für Plugin-Architektur über viele Jahre entworfen und implementiert. (Ich habe ein wenig über das ursprüngliche Design von MEF im Jahr 2004 IIRC gearbeitet.) Sie wollen wirklich versuchen, den Aufwand von fünf Jahren Arbeit von professionellen Architekten in diesem Raum zu kopieren? –

6

Als Neben Antwort, ich benutze diese 2-Schnittstellen für die Implementierung dass

///<summary> 
///</summary> 
public interface IPlugin { 
    ///<summary> 
    ///</summary> 
    string Name { get; } 
    ///<summary> 
    ///</summary> 
    string Description { get; } 
    ///<summary> 
    ///</summary> 
    string Author { get; } 
    ///<summary> 
    ///</summary> 
    string Version { get; } 

    ///<summary> 
    ///</summary> 
    IPluginHost Host { get; set; } 

    ///<summary> 
    ///</summary> 
    void Init(); 
    ///<summary> 
    ///</summary> 
    void Unload(); 

    ///<summary> 
    ///</summary> 
    ///<returns></returns> 
    IDictionary<int, string> GetOptions(); 
    ///<summary> 
    ///</summary> 
    ///<param name="opcion"></param> 
    void ExecuteOption(int option); 

} 



///<summary> 
///</summary> 
public interface IPluginHost { 
    ///<summary> 
    ///</summary> 
    IDictionary<string, object> Variables { get; } 
    ///<summary> 
    ///</summary> 
    ///<param name="plugin"></param> 
    void Register(IPlugin plugin); 
}