2009-08-11 14 views
1

私は将来の開発者がアプリケーション用のプラグインを作成できるwinformsプロジェクトを持っています。 Winformsアプリケーションには、開発者がプラグインの作成時に参照する必要があるすべてのインターフェイスとクラスが含まれています。したがって、私がプラグインを作成するとき、私はメインアプリケーションのdllを参照します。

メインアプリケーションが初期化されるとき、私はすべてのプラグインDLLをロードするための別個のドメインを作成します。私がこれを行うのは、appDomain.unload呼び出しを使って自由にプラグインを削除し、残りのプラグインをリロードすることができるからです。 VS2008でデバッグを開始すると、アプリケーションが初期化され、最初のプラグインがロードされますが、メインアプリケーションのインターフェイスを参照するために使用するプラグインの参照先DLLをロードする必要があるという警告が表示されます。

私の質問は、サブドメインにDLLをロードする前に、メインアプリケーションのインターフェイスを使用してプラグインのインスタンスを参照として使用することができますか?はいの場合、どうすればいいですか?どんな助けもありがとうございます。

これは、app.configファイルにあるプラグインを読み込むアプリケーションのPluginManagerです。私は助けが必要なメソッドとクラスのコンストラクタしか保持していませんでした。 このクラスでは、app.cinfigファイルを読んで、customConfigSectionの内容をcustomConfigコレクションに入れています。 loadAssembliesが呼び出されると、コレクションをループし、コンストラクタで作成されたサブドメインにアセンブリを追加します。アセンブリをプラグインとしてロード

using System; 
using MyApp.Data; 
using MyApp.Interfaces; 
using MyApp.Variables; 
using System.Reflection; 

namespace MyApp.Core 
{ 
    /// <summary> 
    /// This object helps the application manage its scalable and extended components 
    /// called plugins. 
    /// </summary> 
    public class PlugInManager 
    { 
     public PlugInManager() 
     { 

      //appDomain setup 
      pluginDomainSetup = new AppDomainSetup(); 
      pluginDomainSetup.ApplicationBase = pluginDomainLocation; 
      pluginDomainSetup.DisallowCodeDownload = true; 
      string pluginApplicationName = string.Format(MAOIE.Variables.Constants.PLUGIN_APPLICATION_NAME); 

      //appDomain creation 
      pluginDomain = AppDomain.CreateDomain(pluginApplicationName, null, pluginDomainSetup); 

      //Loads the values located in the config file 
      LoadPluginConfiguration(); 
      //Load any existing plugins in the directories 
      LoadAssemblies(); 
     } 

     private void LoadAssemblies() 
     { 
      //I"m thinking I should add this the referenced libraries to the subdomain here. 

      //AppDomain.Unload(this.pluginDomain); 
      string reference = GetReferencePath(); 
      reference += Variables.Constants.MAOIE_CORE_DLL; 


      //Iterate through the items found in the app.config file. 
      foreach (PluginSetting item in this.PluginConfigSettings.PluginItems) 
      { 
       string file = GetPluginPath(); 
       file += item.PluginFileName; 

       switch (item.PluginType) 
       { 
       case Constants.PluginType.pluginTypeA: 
        pluginDomain.CreateInstanceFrom(file, item.PluginAssemblyType); 

        IPluginTypeA ia = (IPluginTypeA)Activator.CreateInstance(pluginDomain, item.PluginFileName, item.PluginAssemblyType); 
        Plugable<IPluginTypeA> pia = new Plugable<IPluginTypeA>(); 
        pia.ConcreteClass = ia; 
        pia.Core = false; 
        //collection used throughout the application 
        this.aerodynamicAnalyzers.Add(pia); 

        return; 
       case Constants.PluginType.pluginTypeB: 
        pluginDomain.CreateInstanceFrom(file, item.PluginAssemblyType); 

        IPluginTypeB ib = (IPluginTypeB)Activator.CreateInstance(pluginDomain, item.PluginFileName, item.PluginAssemblyType); 
        Plugable<IPluginTypeB> pib = new Plugable<IPluginTypeB>(); 
        piB.ConcreteClass = ib; 
        pim.Core = false; 
        //collection used throughout the application 
        this.missionAnalyzers.Add(pib); 
        return; 
       case Constants.PluginType.pluginTypeC: 
        pluginDomain.CreateInstanceFrom(file, item.PluginAssemblyType); 

        IPluginTypeC ic = (IPluginTypeC)Activator.CreateInstance(pluginDomain, item.PluginFileName, item.PluginAssemblyType); 
        Plugable<IPluginTypeC> pic = new Plugable<IPluginTypeC>(); 
        pic.ConcreteClass = ic; 
        pic.Core = false; 
        //collection used throughout the application 
        this.pluginTypeCs.Add(pio); 
        return; 
       case Constants.PluginType.pluginTypeD: 
        pluginDomain.CreateInstanceFrom(file, item.PluginAssemblyType); 

        IPluginTypeD id = (IPluginTypeD)Activator.CreateInstance(pluginDomain, item.PluginFileName, item.PluginAssemblyType); 
        Plugable<IPluginTypeD> piw = new Plugable<IPluginTypeD>(); 
        pid.ConcreteClass = id; 
        pid.Core = false; 
        //collection used throughout the application 
        this.pluginTypeDs.Add(pid); 
        return; 
       } 
      } 
     } 
    } 
    //end PlugInManager 

} 
//end namespace MyApp.Core 

この次のクラスは、別々のプロジェクトでは1つのクラスです。私はpluginManagerのLoadAssembliesメソッドをテストするために空のプラグインをスタブしています。 Visual StudioによってこのプロジェクトのbinディレクトリにコピーされたMyApp.Core.dllへの参照を追加します。メインアプリケーションにあるインタフェースを実装するためには、これが必要です。

このクラスは、ゲッタとセッタに加えて空のメソッドです。

/////////////////////////////////////////////////////////// 
// testPluginA.cs 
// used as an empty class to test the import of plugins into the main application. 
/////////////////////////////////////////////////////////// 
using System; 
using System.Collections.Generic; 
using System.Text; 
using MyApp.Core; 

namespace testPluginA 
{ 
    public class testPluginA : MyApp.Interfaces.IPluginTypeA 
    { 
     public testPluginA() 
     { 

     } 

     private string name = "testPluginA"; 
     private string desc = "Test Plugin A 1"; 
     /// <summary> 
     /// The description of the plugin. 
     /// </summary> 
     public string Description { get{return this.desc;} } 
     /// <summary> 
     /// The display name of the plugin. 
     /// </summary> 
     public string FriendlyName { get{return this.name;} } 
     /// <summary> 
     /// 
     /// </summary> 
     /// <param name="mp"></param> 
     public void Optimize(MyApp.Data.Car car) 
     { 
      //does nothing 
     } 
+0

あなたの質問が正確であるかわかりません。 Visual Studioでデバッグするときに問題がありますか?それとも、実際にアプリケーションをコンパイルするのは問題ですか?またはそれを実行する? –

+0

問題は、アプリケーションを実行しています。最初のプラグインが読み込まれると、プラグインがMyApp.Coreをロードしていないことを示すランタイムエラーが発生します。これが失敗するコード行は、MyApp.Coreを参照として使用するアセンブリをロードしています。その参考は、私が構築したモック・プラグイン・プロジェクトで行われます。 – gsirianni

答えて

2

同じドメインにプラグインをロードしますが、それらは両方LoadUnloadメソッドを公開するインターフェイスを実装します。 Unload方法の公共契約は、以下の[少なくとも]である:GCは、[将来のある時点で]それらを収集できるように、プラグインによって使用されるリソースへ

  • Dispose()適用とnullすべての参照を
  • メインアプリケーションの状態は、プラグインがLoad
有効な運転状態で
  • 場所プラグインがロードされた前と同じであるので、メインアプリケーションに(彼らが何であれフォーム)の「接続」を削除

    この契約を結ぶのはプラグイン作家の責任です。とにかく実行のためにコードをロードしています。ルールが破られた場合、になりますかどうかは、自分のAppDomainに配置するかどうかに関係なくなります。

    編集:個人的に、私はいくつかはここにそうは思わないけれども、あなたが、あなたのAPIを構築するようManaged Extensibility Framework少なくとも調べる価値がある(と、それはあなたのニーズを満たしている場合使用して)だと思います。

  • +0

    同じドメインに配置しなかったのは、ユーザーがファイルプラグインを削除したい場合、dllが解放されて削除されるからです。私がこれを達成できる唯一の方法は、appDomain.Unloadを使用することです。そうしないと、ユーザーがアプリケーションを終了するまで、dllは現在のセッションによってロックされます。あなたの推薦はこれを満たしますか? – gsirianni

    +1

    いいえ、アセンブリのコピーを何らかの並べ替えの一時的なキャッシュに作成し、そこからロードして、そこにプログラムが存在するときにキャッシュをクリアすることができます。 IMOでは、プログラム実行中にプラグインを削除することは、AppDomainのクロス・プラグイン操作のパフォーマンス低下を正当化するまれなケースです。 –

    関連する問題