无法初始化依赖项。使用依赖注入的单例类(Ninject)

时间:2017-08-07 16:42:48

标签: c# dependency-injection ninject

我想要一个应用程序启动后立即使用依赖注入(ninject)的单例类。单例类位于域层(类库)中 -  Domain.Concrete.Operations。我在WebUI层(MVC)中使用此类。 我坚持初始化我计划在Application_Start方法中启动的服务的静态构造函数中的依赖项。什么是正确的方法?

Singleton类:

    namespace Domain.Concrete.Operations
{
    public sealed class SingletonClass
    {
        private IInterface1 _iInterface1;
        private IInterface2 _iInterface2;

        public SingletonClass(IInterface1 iInterface1, IInterface2 iInterface2)
        {
            this._iInterface1 = iInterface1;
            this._iInterface2 = iInterface2;

            StartAllOperations();
        }

        public void StartAllOperations()
        {

        }
    }
}

NinjectDependencyResolver:

    namespace WebUI.Infrastructure
{
    public class NinjectDependencyResolver : IDependencyResolver
    {
        IKernel kernel;

        public NinjectDependencyResolver(IKernel kernelParam)
        {
            kernel = kernelParam;
            AddBindings();

        }

        public object GetService(Type serviceType)
        {
            return kernel.TryGet(serviceType);
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            return kernel.GetAll(serviceType);
        }

        private void AddBindings()
        {
            kernel.Bind<IInterface1>().To<Class1>();
            kernel.Bind<IInterface2>().To<Class2>();

            kernel.Bind<SingletonClass>().To<SingletonClass>().InSingletonScope();
        }
    }
}

据我所知,这段代码将有助于返回相同的SigletonClass实例:

kernel.Bind<SingletonClass>().To<SingletonClass>().InSingletonScope();

App_Start中的服务:

    namespace WebUI.App_Start
{
    public class OperationManagerService
    {

        private IInterface1 _iInterface1;
        private IInterface2 _iInterface2;

        static OperationManagerService() //static constructor cannot have parameters 
         {
            _iInterface1 = //how to initialize 
            _iInterface2 = //interfaces here?
        }

        public static void RegisterService()
        {
            new SingletonClass(_iInterface1, _iInterface2);
        }
    }
}

在Application_Start(Global.asax.cs)中注册服务:

    namespace WebUI
{
    public class MvcApplication : System.Web.HttpApplication
    {


        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            OperationManagerService.RegisterService();
        }
    }
}

更新

我必须承认我能够像这样初始化依赖关系,但是我只能在控制器中使用OperationManagerService类。 不在Application_Start中!

            static OperationManagerService(IInterface1 iInterface1, IInterface2 iInterface2)  
         {
            _iInterface1 = iInterface1;
            _iInterface2 = iInterface2;
        }

这让我想到我不能在Application_Start中使用Ninject注入。如果这是真的,那么创建应该在启动时加载的类的正确位置在哪里?

1 个答案:

答案 0 :(得分:0)

您正在尝试将Singleton patternNinject's Singleton Scope混合,这会混淆谁正在尝试构建什么时候。在尝试使用DI时,请不要使用旧的Singleton模式。 DI的一半要点是管理它包含的对象的生命周期(范围)。您可以通过指定.InSingletonScope()来完成此操作。

现在,关于将依赖项注入启动功能的问题:您需要允许Ninject构造OperationManagerService以便拥有Ninject提供的依赖项。为此,请将其注册到Singleton范围,就像使用SingletonClass一样。从Ninject容器请求第一次,它将被构造并注入必要的参数。 Singleton范围只告诉Ninject只构造一个实例。

但是,您似乎希望在启动期间构建它?如果这是一项要求,则需要提出要求。最简单的解决方案是在绑定后获取它:

private void AddBindings()
{
    kernel.Bind<IInterface1>().To<Class1>();
    kernel.Bind<IInterface2>().To<Class2>();

    kernel.Bind<SingletonClass>().ToSelf().InSingletonScope();
    kernel.Bind<OperationManagerService>().ToSelf().InSingletonScope();

    kernel.Get<OperationManagerService>(); // activate

}

如果你发现自己做了很多,我使用了一个简单的&#34;自动启动&#34;图案:

public interface IAutoStart()
{
    void Start();
}

public class SomeClassThatStarts : IAutoStart
{
    public void Start()
    {
        Console.Log("Starting!");
    }
}

public class AutoStartModule : Ninject.Modules.NinjectModule
{
    public override void Load()
    {
        foreach(var starter in Kernel.GetAll<IAutoStart>())
        {
            starter.Start();
        }
    }
}

在内核中注册AutoStartModule last,任何IAutoStart都会加载任何依赖项并启动。