我可以使用 Ninject 来实例化不依赖的单例服务吗?
Can I use Ninject to instantiate singleton services that nothing depends on?
我的 asp.net mvc 应用程序中有一些服务用于侦听 AMQP 消息和调用方法。
没有控制器依赖于此,因此它不会自行实例化。
我可以手动实例化它,明确地提供它的依赖关系kernel.Get
,但感觉我不应该那样做。
我可以Ninject在单例范围急切实例化类,即使没有其他依赖它吗?
你不能让 ninject 实例化东西,以防你不要求它自己实例化一些东西。
简单的方法是要求 ninject 在组合根处实例化事物:
var kernel = new StandardKernel();
kernel.Bind<IFoo>().To<Foo>();
kernel.Load(AppDomain.CurrentDomain.GetAssemblies()); // loads all modules in assemlby
//...
// resolution root completely configured
kernel.Resolve<IFooSingleton>();
kernel.Resolve<IBarSIngleton>();
实际上还有一种替代方案,虽然不尽相同,但可以达到类似的效果。它要求至少有一个足够快实例化的其他服务:Ninject.Extensions.DependencyCreation。
它是这样工作的:
kernel.Bind<string>().ToConstant("hello");
kernel.Bind<ISingletonDependency>().To<SingletonDependency>()
.InSingletonScope();
kernel.DefineDependency<string, ISingletonDependency>();
kernel.Get<string>();
// when asking for a string for the first time
// ISingletonDependency will be instantiated.
// of course you can use any other type instead of string
为什么
Ninject 不同于其他一些容器(例如 Autofac),而不是 "built" 分阶段。没有先创建绑定,然后创建内核来使用它们的概念。以下是完全合法的:
kernel.Bind<IFoo>()...
kernel.Get<IFoo>()...
kernel.Bind<IBar>()...
kernel.Get<IBar>()...
所以 ninject 不可能知道 何时 您希望实例化单例。使用 autofac it's clear and easy:
var containerBuilder = new ContainerBuilder();
containerBuilder
.RegisterType<Foo>()
.AutoActivate();
var container = containerBuilder.Build(); // now
来自 Java 的 Guice,我非常想念热切的单例模式。它们在例如模块充当插件的场景中很有用。如果您想象服务是从配置中指定的模块组装而成的,那么您可能会看到一个问题,即在应用程序启动时还尝试指定此模块需要的内容 auto-instantiated。
对我来说,模块是定义应用程序组合的地方,将急切的单例分离到代码中的另一个地方感觉更笨重,更不直观。
无论如何,我已经能够非常轻松地将其实现为 Ninject 之上的一层,代码如下:
public static class EagerSingleton
{
public static IBindingNamedWithOrOnSyntax<T> AsEagerSingleton<T>(this IBindingInSyntax<T> binding)
{
var r = binding.InSingletonScope();
binding.Kernel.Bind<IEagerSingleton>().To<EagerSingleton<T>>().InSingletonScope();
return r;
}
}
public interface IEagerSingleton { }
public class EagerSingleton<TComponent> : IEagerSingleton
{
public EagerSingleton(TComponent component)
{
// do nothing. DI created the component for this constructor.
}
}
public class EagerSingletonSvc
{
public EagerSingletonSvc(IEagerSingleton[] singletons)
{
// do nothing. DI created all the singletons for this constructor.
}
}
创建内核后,添加一行:
kernel.Get<EagerSingletonSvc>(); // activate all eager singletons
你在这样的模块中使用它:
Bind<UnhandledExceptionHandlerSvc>().ToSelf().AsEagerSingleton();
我的 asp.net mvc 应用程序中有一些服务用于侦听 AMQP 消息和调用方法。
没有控制器依赖于此,因此它不会自行实例化。
我可以手动实例化它,明确地提供它的依赖关系kernel.Get
,但感觉我不应该那样做。
我可以Ninject在单例范围急切实例化类,即使没有其他依赖它吗?
你不能让 ninject 实例化东西,以防你不要求它自己实例化一些东西。 简单的方法是要求 ninject 在组合根处实例化事物:
var kernel = new StandardKernel();
kernel.Bind<IFoo>().To<Foo>();
kernel.Load(AppDomain.CurrentDomain.GetAssemblies()); // loads all modules in assemlby
//...
// resolution root completely configured
kernel.Resolve<IFooSingleton>();
kernel.Resolve<IBarSIngleton>();
实际上还有一种替代方案,虽然不尽相同,但可以达到类似的效果。它要求至少有一个足够快实例化的其他服务:Ninject.Extensions.DependencyCreation。 它是这样工作的:
kernel.Bind<string>().ToConstant("hello");
kernel.Bind<ISingletonDependency>().To<SingletonDependency>()
.InSingletonScope();
kernel.DefineDependency<string, ISingletonDependency>();
kernel.Get<string>();
// when asking for a string for the first time
// ISingletonDependency will be instantiated.
// of course you can use any other type instead of string
为什么
Ninject 不同于其他一些容器(例如 Autofac),而不是 "built" 分阶段。没有先创建绑定,然后创建内核来使用它们的概念。以下是完全合法的:
kernel.Bind<IFoo>()...
kernel.Get<IFoo>()...
kernel.Bind<IBar>()...
kernel.Get<IBar>()...
所以 ninject 不可能知道 何时 您希望实例化单例。使用 autofac it's clear and easy:
var containerBuilder = new ContainerBuilder();
containerBuilder
.RegisterType<Foo>()
.AutoActivate();
var container = containerBuilder.Build(); // now
来自 Java 的 Guice,我非常想念热切的单例模式。它们在例如模块充当插件的场景中很有用。如果您想象服务是从配置中指定的模块组装而成的,那么您可能会看到一个问题,即在应用程序启动时还尝试指定此模块需要的内容 auto-instantiated。
对我来说,模块是定义应用程序组合的地方,将急切的单例分离到代码中的另一个地方感觉更笨重,更不直观。
无论如何,我已经能够非常轻松地将其实现为 Ninject 之上的一层,代码如下:
public static class EagerSingleton
{
public static IBindingNamedWithOrOnSyntax<T> AsEagerSingleton<T>(this IBindingInSyntax<T> binding)
{
var r = binding.InSingletonScope();
binding.Kernel.Bind<IEagerSingleton>().To<EagerSingleton<T>>().InSingletonScope();
return r;
}
}
public interface IEagerSingleton { }
public class EagerSingleton<TComponent> : IEagerSingleton
{
public EagerSingleton(TComponent component)
{
// do nothing. DI created the component for this constructor.
}
}
public class EagerSingletonSvc
{
public EagerSingletonSvc(IEagerSingleton[] singletons)
{
// do nothing. DI created all the singletons for this constructor.
}
}
创建内核后,添加一行:
kernel.Get<EagerSingletonSvc>(); // activate all eager singletons
你在这样的模块中使用它:
Bind<UnhandledExceptionHandlerSvc>().ToSelf().AsEagerSingleton();