当前位置:  开发笔记 > 编程语言 > 正文

在像体系结构这样的插件中使用Ninject

如何解决《在像体系结构这样的插件中使用Ninject》经验,为你挑选了3个好方法。

我正在学习DI,最近做了我的第一个项目.

在这个项目中,我实现了存储库模式.我有接口和具体实现.我想知道是否有可能将我的接口的实现构建为"插件",我的程序将动态加载的dll.

所以程序可以随着时间的推移而不需要重建它,你只需将dll放在"plugins"文件夹,更改设置和voilá!

这可能吗?Ninject可以帮助解决这个问题吗?



1> ungood..:

虽然Sean Chambers的解决方案适用于您控制插件的情况,但是如果插件可能由第三方开发并且您不希望它们必须依赖于编写ninject模块,则它不起作用.

对于Ninject 的约定扩展,这很容易做到:

public static IKernel CreateKernel()
{
    var kernel = new StandardKernel();

    kernel.Scan(scanner => {
        scanner.FromAssembliesInPath(@"Path\To\Plugins");
        scanner.AutoLoadModules();
        scanner.WhereTypeInheritsFrom();
        scanner.BindWith>();
    });

    return kernel;
}

private class PluginBindingGenerator : IBindingGenerator
{
    private readonly Type pluginInterfaceType = typeof (TPluginInterface);

    public void Process(Type type, Func scopeCallback, IKernel kernel)
    {
        if(!pluginInterfaceType.IsAssignableFrom(type))
            return;
        if (type.IsAbstract || type.IsInterface)
            return;
        kernel.Bind(pluginInterfaceType).To(type);
    }
}

然后,您可以使用所有加载的插件kernel.GetAll().

这种方法的优点是:

    你的插件dll不需要知道他们正在加载ninject

    具体的插件实例将由ninject解析,因此他们可以使用构造函数来注入插件主机知道如何构造的类型.


我在[找到这里](https://github.com/ungood/BadaBingBot/blob/fc326bc37169dfdf506c16115eb6b200f8fc1afd/BadaBingBot/Program.cs)的一个项目中做了相当多的事情.我发现,如果你的某个插件dll没有加载,让Ninject负责实际加载程序集会使你的应用程序崩溃.这不好,所以我首先将程序集加载到app域中,用try/catch包装以获得更好的行为.

2> Sean Chamber..:

这个问题适用于我在此提供的相同答案:NInject可以按需加载模块/组件吗?

我很确定这就是你要找的东西:

var kernel = new StandardKernel();
kernel.Load( Assembly.Load("yourpath_to_assembly.dll");

如果在Ninject.dll中查看带有反射器的KernelBase,您将看到此调用将递归加载已加载程序集中的所有模块(Load方法采用IEnumerable)

public void Load(IEnumerable assemblies)
{
    foreach (Assembly assembly in assemblies)
    {
        this.Load(assembly.GetNinjectModules());
    }
}

我正在使用这种情况,我不希望直接汇编引用会经常更改的内容,我可以换出程序集为应用程序提供不同的模型(授予我适当的测试)


根据GitHub上的Ninject wiki,您可以通过命名程序集Ninject.Extensions.*.dll来自动加载插件.但是,此功能的文档数量少于我在键入过程中的段落.

3> 小智..:

扩展@ungood的良好答案,基于v.2,与Ninject的v.3(目前在RC3上),它可以变得更容易.你不再需要任何IPluginGenerator,只需写:

var kernel = new StandardKernel();
kernel.Bind(scanner => scanner.FromAssembliesInPath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))
                                   .SelectAllClasses()
                                   .InheritedFrom()
                                   .BindToAllInterfaces());

请注意我正在寻找实现IPlugin的插件(将你的界面放在这里)在应用程序的相同路径中.

推荐阅读
家具销售_903
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有