2012-05-07 35 views
1

我在C#.NET中構建了一個插件體系結構,可以從預定義的物理文件路徑動態加載DLL。我知道在組件的內存位置可能存在於兩個位置從而使之不可靠使用類似來驗證組件的成員(接口)的...爲插件體系結構動態加載程序集

if(plugin is T) 
    // cache the assembly 

...所以目前我使用的界面名稱進行比較,然後從中激活實例。但是,這也有侷限性太大,因爲接口「IPlugin」是大量的第三方組件的使用很常見的接口名稱(即log4net的,等等)

看看下面的代碼(這是不工作):

foreach (Type t in assembly.GetTypes()) 
{ 
    type = t; 

    if (!type.IsInterface) 
    { 
     var plugin = type.GetInterface(typeof(T).Name); 

     if (plugin != null) 
      if (plugin is T) 
      { 
       T p = (T)Activator.CreateInstance(type); 

       if (!this.Plugins.Select(sp => sp.Name).Contains(p.Name)) 
        this.Plugins.Add(p); 
      } 
    } 
} 

我的問題:什麼是驗證動態加載的DLL匹配IPlugin接口的最佳(可靠)方法?

一個想法是硬編碼IPlugin的公鑰令牌並驗證,但我想知道是否有更正式的方式。作爲一個例子,我可以想象一個潛在的安全漏洞,程序集會欺騙IPlugin名稱或公鑰標記......所以也許有一種很好的方法來測試加載的DLL是否與加載它的程序集的簽名相匹配。

請讓我知道是否需要更清晰。

非常感謝!

回答

1

使用IsAssignableFrom

var yourIPlugin = typeof(IPlugin); 
foreach (Type t in assembly.GetTypes()) 
{ 
    if (yourIPlugin.IsAssignableFrom(t)) 
    { 
      T p = (T)Activator.CreateInstance(t); 
      if (!this.Plugins.Select(sp => sp.Name).Contains(p.Name)) 
       this.Plugins.Add(p); 
    } 
} 

IsAssignableFrom使用類型是否有其他類型可以從它被分配。它充分考慮到實際的類型,而不僅僅是類型的名稱。因此,即使您的組件或其他組件包含名爲IPlugin的類型,也只能找到yourIPlugin中的一個。

2

我解決它像這樣:

public List<T> LoadPluginsFromPath<T>(string Path) {   
    List<T> results = new List<T>(); 

    DirectoryInfo Directory = new DirectoryInfo(Path); 
    if (!Directory.Exists) { 
     return results; // Nothing to do here 
    } 

    FileInfo[] files = Directory.GetFiles("*.dll"); 
    if (files != null && files.Length > 0) { 
     foreach (FileInfo fi in files) { 
      List<T> step = LoadPluginFromAssembly(fi.FullName); 
      if (step != null && step.Count > 0) { 
       results.AddRange(step); 
      } 
     } 
    } 

    return results; 
} 

private List<T> LoadPluginFromAssembly<T>(string Filename) { 
    List<T> results = new List<T>(); 

    Type pluginType = typeof(T); 

    Assembly assembly = Assembly.LoadFrom(Filename); 
    if (assembly == null) { 
     return results; 
    } 

    Type[] types = assembly.GetExportedTypes(); 
    foreach (Type t in types) { 

     if (!t.IsClass || t.IsNotPublic) { 
      continue; 
     } 

     if (pluginType.IsAssignableFrom(t)) { 
      T plugin = Activator.CreateInstance(t) as T; 
      if (plugin != null) { 
       results.Add(plugin); 
      } 
     } 

    } 

    return results; 
} 

我叫它像這樣:

裝配枚舉所有類型的
List<MyPlugin> plugins = LoadPluginsFromPath<MyPlugin>("plugins"); 
1

Insteas,你爲什麼不定義一個工廠類?

工廠類將有一個更合適的名稱,例如「YourFramework.PluginTypeFactory」,確實消除了可能的名稱衝突。

此外,Assembly.GetTypes可能fail嚴重某些程序集,並花費大量的時間在錯誤程序集上。

1

我正好爲你做什麼,一些「插件」加載兩次和.NET Framework是不能夠解決的各類使用

IsAssignableFrom 

當我解決它添加一個處理程序來有同樣的問題AppDomain的AssemblyResolve事件,如果它已經加載到當前AppDomain的Assemblies集合中,則不會再次加載「Plugin」。

它發生的最多時,一些插件開始取決於對方和Assembly加載器瘋狂地加載相同的程序集時,他們已經加載。

希望它有助於解決您的問題,它肯定讓我瘋狂!