我可以使用Ninject实例化不依赖于任何东西的单例服务吗?

本文关键字:单例 服务 任何东 依赖于 可以使 Ninject 实例化 我可以 | 更新日期: 2023-09-27 18:02:52

我的asp.net mvc应用程序中有一些服务侦听AMQP消息并调用方法。

没有控制器依赖于它,所以它不会被自己实例化。

我可以手动实例化它,显式地提供它与kernel.Get的依赖关系,但感觉我不应该这样做。

我可以使Ninject在单例作用域急切地实例化类,即使没有其他依赖于它?

我可以使用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),它不是分阶段"构建"的。没有先创建绑定,然后再创建内核来使用它们的概念。以下是完全合法的:

kernel.Bind<IFoo>()...
kernel.Get<IFoo>()...
kernel.Bind<IBar>()...
kernel.Get<IBar>()...

so ninject不可能知道你想要实例化的单例。使用autoface,它是清晰和容易的:

var containerBuilder = new ContainerBuilder();
containerBuilder
    .RegisterType<Foo>()
    .AutoActivate();
var container = containerBuilder.Build(); // now

来自Java的Guice,我非常怀念急切单例模式。它们在模块充当插件的场景中非常有用。如果您想象一个服务是由配置中指定的模块组装而成的,那么您可能会发现一个问题,即当应用程序启动时,还试图指定该模块需要自动实例化的内容。

对我来说,模块是定义应用程序组合的地方,将渴望的单例分离到代码中的另一个地方感觉更笨拙,更不直观。

无论如何,我已经能够很容易地实现这个图层在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();