动态加载插件体系结构的程序集



>我在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 是否与加载它的程序集的签名匹配。

如果需要更清楚,请告诉我。

非常感谢!

我是这样解决的:

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

使用 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 中的类型。

枚举

汇编中的所有类型,为什么不定义一个工厂类?

工厂类将有一个更合适的名称,例如"YourFramework.PluginTypeFactory",确实消除了可能的名称冲突。

此外,Assembly.GetTypes可能会在某些程序集上严重失败,并且在错误程序集上花费大量时间。

我碰巧遇到了和你一样的问题,一些"插件"被加载了两次,并且 .NET Framework 在使用时无法解析这些类型

IsAssignableFrom

我解决了将处理程序添加到 AppDomain 的 AssemblyResolve 事件的问题,如果它已经加载到当前 AppDomain 的程序集集合中,则不会再次加载"插件"。

当一些插件开始相互依赖并且程序集加载器在已经加载相同的程序集时一遍又一遍地加载相同的程序集时,这种情况最常发生。

希望它能帮助解决你的问题,它肯定会让我发疯!

最新更新