【问题标题】:Fail to initialize dependencies. Singleton class using Dependency Injection (Ninject)无法初始化依赖项。使用依赖注入 (Ninject) 的单例类
【发布时间】:2018-01-15 01:14:59
【问题描述】:

我想要一个使用依赖注入 (ninject) 的单例类在应用程序启动后立即启动。单例类驻留在领域层(类库) - 领域.具体.操作。我在 WebUI 层(MVC)中使用这个类。 我被困在我计划在 Application_Start 方法中启动的服务的静态构造函数中初始化依赖项。正确的做法是什么?

单例类:

    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 注入。如果是真的,那么在哪里创建一个应该在启动时加载的类?

【问题讨论】:

    标签: c# dependency-injection ninject


    【解决方案1】:

    您试图将Singleton patternNinject's Singleton Scope 混合在一起,这会混淆谁试图在何时构建什么。尝试使用 DI 时不要使用旧的 Singleton 模式。 DI 的一半意义在于管理其包含的对象的生命周期(范围)。您可以通过指定.InSingletonScope() 来执行此操作。

    现在,关于将依赖项注入启动功能的问题:您需要允许 Ninject 构造 OperationManagerService 才能获得 Ninject 提供的依赖项。为此,请将其注册到 Singleton 范围内,就像使用 SingletonClass 一样。 第一次从 Ninject 容器请求它,它将被构造并注入必要的参数。单例作用域只告诉 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
    
    }
    

    如果你发现自己经常这样做,我使用了一个简单的“自动启动”模式:

    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,任何IAutoStart 都将加载任何依赖项并启动。

    【讨论】:

    • 非常感谢戴夫!确实,我添加了 kernel.Get();到我的 AddBinding 方法,它在启动时创建了所需的实例。我还将阅读您附在帖子中的链接!再次感谢!祝你有美好的一天!!!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-06
    • 2013-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多