2009-08-11 46 views
1

我有一個winforms項目,它允許未來的開發人員爲appplication創建插件。 Winforms應用程序包含開發人員在創建插件時需要引用的所有接口和類。因此,當我創建插件時,我會引用主應用程序的dll。

當主應用程序初始化時,我創建一個單獨的域來加載所有的插件DLL。我這樣做的原因是,我可以使用appDomain.unload調用來隨意刪除插件,然後重新加載剩餘的插件。 當我在VS2008中啓動調試時,我的應用程序初始化,它加載第一個插件,但我得到一個警告,我需要加載插件引用的dll,我用它來引用主應用程序的接口。

現在我的問題是在將dll加載到子域之前,我可以使用主應用程序的接口來創建插件的實例以供插件用作參考?如果是的話,我該怎麼做?任何幫助表示讚賞。

這是我的應用程序的PluginManager,它加載了app.config文件中找到的插件。我只保留了我需要幫助的方法和類的構造函數。 在這個類中,我正在讀取一個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 

這個下一個班級是一個單獨的班級在一個單獨的項目。我正在插入一個空插件來測試我的pluginManager的LoadAssemblies方法。我將由Visual Studio複製的MyApp.Core.dll引用添加到此項目的bin目錄中。我需要這個以實現在主應用程序中找到的接口。

這個類只是getters和setters加上一個空方法。

/////////////////////////////////////////////////////////// 
// 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中調試時會出現問題嗎?或者它實際上是編譯應用程序的問題?或者在運行它? – 2009-08-11 19:54:46

+0

問題在於運行應用程序。當我的第一個插件加載時,我得到一個運行時錯誤,指出我的插件沒有加載MyApp.Core。代碼行失敗的地方是加載我的程序集,它使用MyApp.Core作爲參考。該引用是在我構建的模擬插件項目中進行的。 – gsirianni 2009-08-11 20:12:35

回答

2

加載插件到相同的域名,但讓他們實現暴露既是LoadUnload方法的接口。該Unload方法的公共合同(至少)以下內容:

  • Dispose()適用和null於使用插件使GC可以[在未來的某個時刻]收集他們的資源的所有引用
  • 刪除它的「連接」(它們可以是任何形式)到主應用程序,以便在主應用程序的狀態是一樣的前插件加載
  • 放置的狀態下的插件,其中Load是一個有效的操作

您的插件作者有責任滿足此合同。無論如何,你正在加載他們的代碼執行 - 如果他們違反規則,出錯,不管你是否將它們放在他們自己的AppDomain中。

編輯:就個人而言,我認爲Managed Extensibility Framework至少值得研究的(和使用是否符合您的需求),爲您打造自己的API,但這裏的一些人會不同意。

+0

我沒有把它放在同一個域中的原因是因爲如果用戶想要刪除文件插件,dll會被釋放並刪除。我可以實現這一點的唯一方法是使用appDomain.Unload。否則,dll仍然會被當前會話鎖定,直到用戶退出應用程序。你的建議會滿足這個嗎? – gsirianni 2009-08-11 20:23:39

+1

不,但是您可以將程序集的副本創建爲某種類型的臨時高速緩存,然後從該高速緩存中加載該程序集,並在程序存在時清除高速緩存。國際海事組織,在程序運行確定的時候刪除一個插件是一個很少見的情況,以證明跨AppDomain插件操作的性能下降。 – 2009-08-11 20:39:38