我正在学习DI,最近做了我的第一个项目.
在这个项目中,我实现了存储库模式.我有接口和具体实现.我想知道是否有可能将我的接口的实现构建为"插件",我的程序将动态加载的dll.
所以程序可以随着时间的推移而不需要重建它,你只需将dll放在"plugins"文件夹,更改设置和voilá!
这可能吗?Ninject可以帮助解决这个问题吗?
虽然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解析,因此他们可以使用构造函数来注入插件主机知道如何构造的类型.
这个问题适用于我在此提供的相同答案:NInject可以按需加载模块/组件吗?
我很确定这就是你要找的东西:
var kernel = new StandardKernel(); kernel.Load( Assembly.Load("yourpath_to_assembly.dll");
如果在Ninject.dll中查看带有反射器的KernelBase,您将看到此调用将递归加载已加载程序集中的所有模块(Load方法采用IEnumerable)
public void Load(IEnumerableassemblies) { foreach (Assembly assembly in assemblies) { this.Load(assembly.GetNinjectModules()); } }
我正在使用这种情况,我不希望直接汇编引用会经常更改的内容,我可以换出程序集为应用程序提供不同的模型(授予我适当的测试)
扩展@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的插件(将你的界面放在这里)在应用程序的相同路径中.