2009-07-01 9 views
28

Próbuję napisać system wtyczek, aby zapewnić pewną rozszerzalność aplikacji, aby ktoś mógł napisać wtyczkę do aplikacji bez dotykania kodu głównego aplikacji (i ryzykując zerwanie czegoś).Pisanie systemu C# Plugin

Mam podstawa „IPlugin” interfejs napisany (ATM, nic nie jest jeszcze zaimplementowane)

Oto jak jestem ładowania:

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

Przyjaciel starał się pomóc, ale ja naprawdę nie rozumiem, co było nie tak.

Struktura folderów dla wtyczek jest następujący:

\
\ plugins \

Wszystkie pluginy odwołać .dll nazwie "Lab.Core.dll" w katalogu [Root] i nie występuje w katalogu wtyczek z powodu ładowania zduplikowanych referencji.

System wtyczek jest ładowany z pliku Lab.Core.dll, do którego odwołuje się również mój plik wykonywalny. Wpisz "IPlugin" również w pliku Lab.Core.dll. Lab.Core.dll jest, dokładnie tak nazwany, rdzeniem mojej aplikacji.

EDIT:

Pytanie: Dlaczego/Co to jest wyjątek Dostaję i jak mogę go naprawić?

FINAL EDIT:

Ok, więc postanowiłem napisać go ponownie po patrząc na niektóre kodu źródłowego przyjaciel napisał dla regulatora TF2.

Oto co mam i to działa:

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

I pamiętać, że nie zostały faktycznie zadał pytanie, właśnie opisany, co próbujesz zrobić. Czy mógłbyś sformułować swoje pytanie w formie pytania? –

+1

Błąd. Przykro mi, ale odłożyłem słuchawkę, próbując wyjaśnić, co robię, ale zapomniałem o tym. : x Dokonam tej edycji. – Zack

+1

Prosimy o przesłanie pełnego otrzymanego wyjątku, wraz ze stosem śledzenia i wszelkimi wewnętrznymi wyjątkami. Opublikuj wyniki ex.ToString(). –

Odpowiedz

7

Brzmi jak masz odwołanie cykliczne. Mówiłeś, że twoje wtyczki odwołują się do Lab.Core.DLL, ale mówisz też, że wtyczki są ładowane z Lab.Core.DLL.

Czy nie rozumiem, co się tutaj dzieje?

EDIT: OK, teraz, że dodałeś swoje pytanie na pytanie ...

Trzeba mieć Lab.Core.DLL dostępne wtyczki są ładowane ponieważ jest to uzależnienie. Zwykle oznaczałoby to, że znajduje się w tym samym katalogu lub w GAC.

Podejrzewam, że w grę wchodzą głębsze problemy z projektowaniem, ale to jest twój bezpośredni problem.

+0

Dzięki za pomoc. Skończyłem na przepisywaniu go na podstawie kodu surnce przyjaciela. Zmieniono oryginalny wpis, aby uwzględnić moje rozwiązanie. :) – Zack

28

Managed Extensibility Framework (MEF) to nowa biblioteka w .NET, który umożliwia większą ponowne wykorzystanie aplikacji i komponentów. Dzięki aplikacjom MEF aplikacje .NET mogą przekształcić się statycznie w skompilowane dynamicznie. Jeśli budujesz rozszerzalne aplikacje, rozszerzalne frameworki i rozszerzenia aplikacji, to MEF jest dla Ciebie.

http://www.codeplex.com/MEF

EDIT: CodePlex odchodzi - kod został przeniesiony do Github wyłącznie dla celów archiwalnych: https://github.com/MicrosoftArchive/mef

+4

Zostało to przeniesione do codeplex: http://www.codeplex.com/ MEF –

+1

To powinno być naprawdę możliwe bez użycia MEF. –

+10

Oczywiście jest to możliwe bez użycia MEF. W MEF nie ma nic magicznego. Ale MEF został zaprojektowany i wdrożony przez ekspertów od architektury wtyczek przez wiele lat. (Pracowałem trochę nad początkowym projektem MEF w 2004 r. IIRC.) Naprawdę chcesz spróbować powtórzyć wysiłek pięciu lat pracy pro architektów w tej przestrzeni? –

6

Jako odpowiedź bocznej, i wykorzystać te 2 interfejsy do realizacji że

///<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); 
}