无法初始化依赖项。使用依赖注入的单例 class (Ninject)
Fail to initialize dependencies. Singleton class using Dependency Injection (Ninject)
我想要一个使用依赖注入 (ninject) 的单例 class 在应用程序启动时立即启动。单例 class 位于域层(Class 库)-
Domain.Concrete.Operations。我在 WebUI 层 (MVC) 中使用这个 class。
我坚持在我计划在 Application_Start 方法中启动的服务的静态构造函数中初始化依赖项。正确的做法是什么?
单例class:
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();
}
}
}
据我了解,此代码将有助于 return 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 class。 不在 Application_Start!
static OperationManagerService(IInterface1 iInterface1, IInterface2 iInterface2)
{
_iInterface1 = iInterface1;
_iInterface2 = iInterface2;
}
这让我想到我不能在 Application_Start 中使用 Ninject 进行注入。如果是这样,那么创建应在启动时加载的 class 的正确位置在哪里?
您正在尝试混合 Singleton pattern with Ninject'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
}
如果您发现自己经常这样做,我使用了一个简单的 "auto-start" 模式:
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
都将加载任何依赖项并启动。
我想要一个使用依赖注入 (ninject) 的单例 class 在应用程序启动时立即启动。单例 class 位于域层(Class 库)- Domain.Concrete.Operations。我在 WebUI 层 (MVC) 中使用这个 class。 我坚持在我计划在 Application_Start 方法中启动的服务的静态构造函数中初始化依赖项。正确的做法是什么?
单例class:
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();
}
}
}
据我了解,此代码将有助于 return 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 class。 不在 Application_Start!
static OperationManagerService(IInterface1 iInterface1, IInterface2 iInterface2)
{
_iInterface1 = iInterface1;
_iInterface2 = iInterface2;
}
这让我想到我不能在 Application_Start 中使用 Ninject 进行注入。如果是这样,那么创建应在启动时加载的 class 的正确位置在哪里?
您正在尝试混合 Singleton pattern with Ninject'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
}
如果您发现自己经常这样做,我使用了一个简单的 "auto-start" 模式:
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
都将加载任何依赖项并启动。