2009-07-01 23 views
28

Estoy tratando de escribir un sistema de complemento para proporcionar algo de extensibilidad a una aplicación mía para que alguien pueda escribir un plugin para la aplicación sin tocar el código de la aplicación principal (y arriesgarse a romper algo).Escribiendo el sistema de complemento C#

Tengo la base "IPlugin" interfaz escrita (atm, nada se ha implementado todavía)

Así es como estoy de carga:

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

Un amigo trató de ayudar pero realmente no entendí lo que estaba mal.

La estructura de carpetas para los plugins es la siguiente:

\
\ Plugins \

Referencia Todos los plugins un .dll denominado "Lab.Core.dll" en el directorio [root] y no está presente en el directorio de complementos debido a la carga de referencias duplicadas.

El sistema de complemento se carga desde Lab.Core.dll al que también hace referencia mi ejecutable. Escriba "IPlugin" también en Lab.Core.dll. Lab.Core.dll es, exactamente como el nombre, el núcleo de mi aplicación.

EDIT:

Pregunta: ¿Por qué/¿Qué es esa excepción que estoy recibiendo y cómo podría ir sobre la fijación él?

edición final:

Ok, así que decidí volver a escribir después de ver algo de código fuente de un amigo escribió para un regulador de TF2.

Aquí es lo que tengo y funciona:

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

observo que usted no ha hecho una pregunta, que ha acaba de describir lo que estás tratando de hacer. ¿Podría formular su pregunta en forma de pregunta? –

+1

Err. Lo siento, me quedé colgado tratando de explicar lo que estaba haciendo, pero olvidé la pregunta. : x Haré esa edición. – Zack

+1

Por favor, publique la excepción completa que recibió, completa con el seguimiento de la pila y cualquier excepción interna. Publique los resultados de ex.ToString(). –

Respuesta

7

Parece que usted tiene una referencia circular. Dijo que sus complementos hacen referencia a Lab.Core.DLL, pero también dice que los complementos se cargan desde Lab.Core.DLL.

¿Estoy entendiendo mal lo que está sucediendo aquí?

EDIT: OK ahora que se han añadido a tu pregunta a la pregunta ...

Es necesario tener Lab.Core.DLL accesible para el plugin que se carga, ya que es una dependencia. Normalmente eso significaría tenerlo en el mismo directorio o en el GAC.

Sospecho que hay problemas de diseño más profundos en juego aquí, pero este es su problema inmediato.

+0

Gracias por la ayuda. Terminé reescribiéndolo en base al código soruce de un amigo. Publicación original editada para incluir mi solución. :) – Zack

28

El Marco Extensibilidad Administrada (MEF) es una nueva biblioteca de .NET que permite una mayor reutilización de aplicaciones y componentes. Usando MEF, las aplicaciones .NET pueden hacer que el cambio sea compilado estáticamente a compuesto dinámicamente. Si está creando aplicaciones extensibles, marcos extensibles y extensiones de aplicaciones, entonces MEF es para usted.

http://www.codeplex.com/MEF

Editar: CodePlex se va - el código ha sido trasladado a Github para fines de archivo: https://github.com/MicrosoftArchive/mef

+4

Esto se movió a codeplex: http://www.codeplex.com/ MEF –

+1

Esto realmente debería ser posible sin el uso de MEF. –

+10

Por supuesto es posible sin el uso de MEF. No hay nada mágico en MEF. Pero el MEF fue diseñado e implementado por expertos en arquitectura de complementos durante muchos años. (Trabajé un poco en el diseño inicial de MEF en 2004 IIRC.) ¿Realmente desea duplicar el esfuerzo de cinco años de trabajo de los arquitectos profesionales en este espacio? –

6

Como respuesta lado, utilizo estos 2 interfaces de aplicación de dicha

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