我有一个支持插件的应用程序。这些插件是加载到独立应用程序域中的DLL集。我的主应用程序在这些域中查找类(通过Ninject.Extensions.Conventions)继承自IPlugin
,并以下列方式将这些类绑定到具体的插件实现:
var kernel = new StandardKernel();
kernel.Bind(scanner => scanner.From(pluginAssemblies).SelectAllClasses()
.InheritedFrom<IPlugin>().BindWith<CustomBindingGenerator<IPlugin>>());
//CustomBindingGenerator
public class CustomBindingGenerator<TInterface> : IBindingGenerator
{
public static readonly string MetadataKey = "PluginKey";
public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
{
Type interfaceType = typeof(TInterface);
if (!interfaceType.IsAssignableFrom(type))
yield return null;
yield return (IBindingWhenInNamedWithOrOnSyntax<object>)bindingRoot.Bind(interfaceType).To(type).WithMetadata(MetadataKey, type.FullName);
}
}
这一切都很好 - 插件已加载,然后可以根据需要旋转并执行。当我尝试向插件本身提供依赖注入功能时,我的问题就出现了,因此插件可以使用构造函数注入来实现其特定的应用程序依赖性。我让每个插件定义了一个IDependencySpecification
,它传递了对同一个内核的引用,该内核保存了程序集中所有插件的绑定(即,上面的kernel
相同):
public class MyPluginDependencySpecification : IDependencySpecification
{
public void SetupDependencies(IKernel kernel)
{
kernel.Bind<IMyService>().To<MyService>();
....
}
}
这很有效 - 只要主应用程序使用的Ninject版本与插件正在使用的Ninject版本相同。一些较新的插件开始依赖需要更新版本的Ninject的库,并且在尝试加载此IDependencySpecification
时,我的主应用程序抛出一个错误,说它没有实现SetupDependencies
方法。
总之,即使我试图以几乎所有方式(通过应用程序域等)将我的插件与我的应用程序隔离,但这个Ninject引用正在泄漏(必要时)并且现在开始导致版本冲突错误。 有没有办法可以重构这个架构以避免这个问题,并且仍然允许我的插件指定自己的依赖注入绑定?
答案 0 :(得分:1)
当插件需要使用与程序正在使用的相同版本的ninject时,但依赖于不同版本的功能,......那就是无法正常工作。
我们可以改变两件事
通过实现类似于ninject child kernel extension的内容,可以消除对使用相同IoC版本的限制:
应用程序创建并使用主内核。 每个插件都使用它自己的IoC。 Ninject,Unity,Autofac,你的名字。 IoC以某种方式进行扩展,当它本身无法满足请求时,它会将其传递到应用程序的主内核。
您需要提供访问主内核的界面。您还需要特定于容器的“子内核”扩展实现,这些实现可能需要在IoC更新时进行更新。
子内核实现实际上很小,请参阅https://github.com/ninject/ninject.extensions.childkernel/blob/master/src/Ninject.Extensions.ChildKernel/ChildKernel.cs