将 Nininject MVC 与 class 个库一起使用
Using Nininject MVC with class libraries
我对 IoC 框架很陌生,所以请原谅我的术语。
所以我拥有的是一个带有 Nininject MVC 引用的 MVC 项目。
我的项目中还有其他 class 库,例如域层,我希望能够在那里使用 Ninject 框架,但我的所有绑定都在 MVC 项目的 App_Start
文件夹下的 NinjectWebCommon.cs
中:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IHardwareService>().To<WindowsHardwareService>();
kernel.Bind<IStatusApi>().To<StatusApiController>();
}
目前在我的 class 库中,我正在使用构造函数注入,但有时我不得不对依赖项进行硬编码:
var service = new WindowsHardwareService();
当我希望能够执行以下操作时:
IKernel kernel = new StandardKernel(.....);
var context = kernel.Get<IHardwareService>();
因为我没有任何模块,所以我没有进行以下操作?
我阅读的所有文档主要针对常规 Ninject 库而不是 MVC 版本。
我需要做什么,如何将常规 Ninject 库与 MVC 版本一起使用?
更新
这是我试过的:
这样做的目的是为了让每个项目都能加载模块,得到当前注入的接口。
App_Start/NinjectWebCommon.cs(在 MVC 项目中)
private static void RegisterServices(IKernel kernel)
{
var modules = new IoCModules();
var newKernal = modules.GetKernel();
kernel = newKernal;
}
IoCModules.cs(在Project.Ioc项目中)
public class IoCModules
{
public IKernel GetKernel()
{
var modules = new CoreModule();
return modules.Kernel;
}
}
CoreModule.cs(在 Project.IoC.Modules 项目中)<-- 这是对所有项目的所有引用所在的位置,这解决了任何循环依赖问题.
public class CoreModule : NinjectModule
{
public override void Load()
{
Bind<IHardwareService>().To<WindowsHardwareService>();
Bind<IStatusApi>().To<StatusApiController>();
}
}
但我目前得到以下信息:
Error activating IHardwareService
No matching bindings are available, and the type is not self-bindable.
Activation path:
2) Injection of dependency IHardwareService into parameter service of constructor of type DashboardController
1) Request for DashboardController
Suggestions:
1) Ensure that you have defined a binding for IHardwareService.
2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
3) Ensure you have not accidentally created more than one kernel.
4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
5) If you are using automatic module loading, ensure the search path and filters are correct.
看来你有很多问题需要在这里回答,所以我会尽力而为。
根据您当前的问题,我将尝试"draw up"您当前实现的简化架构:
- 领域层:你领域的核心,你的业务实体所在的地方等
- 基础架构层:这是您的服务所在的位置,例如:
WindowsHardwareService
- IOC:我倾向于将此称为
DependencyResolution
集会。
- UI: MVC 应用程序
假设以上所有这些,我们可以声明您的应用程序 Composition Root
or Entry point
is the UI MVC project. One of the main concepts using a DI Container
that is you initalize it in the Composition Root
set up/do all your needed bindings and registrations here. The main intention to do it in the entry point is to avoid the Service Locator
反模式。
通过使用 DI Container
,您不会 new()
升级 class 实现或获取内核,而是按照 [=34= 的规则请求注册的依赖项] 或也称为好莱坞原则。
完成哲学课程后,我们终于可以进行一些实际的实施了。
在您的 IOC 程序集中创建一个 Ninject module:,我们将此文件称为 ServiceModule.cs
using Ninject.Modules;
public class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<IHardwareService>().To<WindowsHardwareService>();
Bind<IStatusApi>().To<StatusApiController>();
}
}
这将是您将在 Composition Root
中 register/load 的 Ninject module
。
现在关于组合根: 在 UI MVC 项目 NinjectWebCommon.cs
你可以有一个方法负责加载你的模块,如下所示。
private static void RegisterServices(IKernel kernel)
{
var modules = new List<INinjectModule>
{
new ServiceModule()
//, new FooModule()
//, new BarModule()
};
kernel.Load(modules);
}
最后是 UI MVC 中的 DashboardController
:
public class DashboardController : Controller
{
private readonly IHardwareService _hardwareService;
public DashboardController(IHardwareService hardwareService)
{
_hardwareService = hardwareService;
}
}
此时,您要求在控制器构造函数中注册 IHardwareService
的实现。 DI Container
将完成肮脏的工作并向您传递您稍后可以在控制器中使用的实例。
关于 接口 的注释:我倾向于将它们放入自己的程序集中,我只在其中存储接口,例如:Project.Domain.Interfaces
或 Project.Infrastructure.Interfaces
其中每个程序集仅包含域或基础结构接口。
程序集之间的引用:
为了将所有这些放在一起,UI 仅引用 IOC 程序集和 接口 包含您在 Ninject Module
中绑定的接口的程序集。
综上所述:
您的 classes 和接口本身只是碎片,DI 容器正在粘合 在一起。
希望我整理了一下。
编辑: 作为 @AndreySarafanov 在评论中指出的一些好建议,如果您需要您要求的接口的不同实现在构造函数中,您可以使用 Ninject Factory. For more information you can refer to this 答案。
我对 IoC 框架很陌生,所以请原谅我的术语。
所以我拥有的是一个带有 Nininject MVC 引用的 MVC 项目。
我的项目中还有其他 class 库,例如域层,我希望能够在那里使用 Ninject 框架,但我的所有绑定都在 MVC 项目的 App_Start
文件夹下的 NinjectWebCommon.cs
中:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IHardwareService>().To<WindowsHardwareService>();
kernel.Bind<IStatusApi>().To<StatusApiController>();
}
目前在我的 class 库中,我正在使用构造函数注入,但有时我不得不对依赖项进行硬编码:
var service = new WindowsHardwareService();
当我希望能够执行以下操作时:
IKernel kernel = new StandardKernel(.....);
var context = kernel.Get<IHardwareService>();
因为我没有任何模块,所以我没有进行以下操作? 我阅读的所有文档主要针对常规 Ninject 库而不是 MVC 版本。
我需要做什么,如何将常规 Ninject 库与 MVC 版本一起使用?
更新
这是我试过的:
这样做的目的是为了让每个项目都能加载模块,得到当前注入的接口。
App_Start/NinjectWebCommon.cs(在 MVC 项目中)
private static void RegisterServices(IKernel kernel)
{
var modules = new IoCModules();
var newKernal = modules.GetKernel();
kernel = newKernal;
}
IoCModules.cs(在Project.Ioc项目中)
public class IoCModules
{
public IKernel GetKernel()
{
var modules = new CoreModule();
return modules.Kernel;
}
}
CoreModule.cs(在 Project.IoC.Modules 项目中)<-- 这是对所有项目的所有引用所在的位置,这解决了任何循环依赖问题.
public class CoreModule : NinjectModule
{
public override void Load()
{
Bind<IHardwareService>().To<WindowsHardwareService>();
Bind<IStatusApi>().To<StatusApiController>();
}
}
但我目前得到以下信息:
Error activating IHardwareService
No matching bindings are available, and the type is not self-bindable. Activation path:
2) Injection of dependency IHardwareService into parameter service of constructor of type DashboardController
1) Request for DashboardController
Suggestions:
1) Ensure that you have defined a binding for IHardwareService.
2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
3) Ensure you have not accidentally created more than one kernel.
4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
5) If you are using automatic module loading, ensure the search path and filters are correct.
看来你有很多问题需要在这里回答,所以我会尽力而为。
根据您当前的问题,我将尝试"draw up"您当前实现的简化架构:
- 领域层:你领域的核心,你的业务实体所在的地方等
- 基础架构层:这是您的服务所在的位置,例如:
WindowsHardwareService
- IOC:我倾向于将此称为
DependencyResolution
集会。
- IOC:我倾向于将此称为
- UI: MVC 应用程序
假设以上所有这些,我们可以声明您的应用程序 Composition Root
or Entry point
is the UI MVC project. One of the main concepts using a DI Container
that is you initalize it in the Composition Root
set up/do all your needed bindings and registrations here. The main intention to do it in the entry point is to avoid the Service Locator
反模式。
通过使用 DI Container
,您不会 new()
升级 class 实现或获取内核,而是按照 [=34= 的规则请求注册的依赖项] 或也称为好莱坞原则。
完成哲学课程后,我们终于可以进行一些实际的实施了。
在您的 IOC 程序集中创建一个 Ninject module:,我们将此文件称为 ServiceModule.cs
using Ninject.Modules;
public class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<IHardwareService>().To<WindowsHardwareService>();
Bind<IStatusApi>().To<StatusApiController>();
}
}
这将是您将在 Composition Root
中 register/load 的 Ninject module
。
现在关于组合根: 在 UI MVC 项目 NinjectWebCommon.cs
你可以有一个方法负责加载你的模块,如下所示。
private static void RegisterServices(IKernel kernel)
{
var modules = new List<INinjectModule>
{
new ServiceModule()
//, new FooModule()
//, new BarModule()
};
kernel.Load(modules);
}
最后是 UI MVC 中的 DashboardController
:
public class DashboardController : Controller
{
private readonly IHardwareService _hardwareService;
public DashboardController(IHardwareService hardwareService)
{
_hardwareService = hardwareService;
}
}
此时,您要求在控制器构造函数中注册 IHardwareService
的实现。 DI Container
将完成肮脏的工作并向您传递您稍后可以在控制器中使用的实例。
关于 接口 的注释:我倾向于将它们放入自己的程序集中,我只在其中存储接口,例如:Project.Domain.Interfaces
或 Project.Infrastructure.Interfaces
其中每个程序集仅包含域或基础结构接口。
程序集之间的引用:
为了将所有这些放在一起,UI 仅引用 IOC 程序集和 接口 包含您在 Ninject Module
中绑定的接口的程序集。
综上所述:
您的 classes 和接口本身只是碎片,DI 容器正在粘合 在一起。
希望我整理了一下。
编辑: 作为 @AndreySarafanov 在评论中指出的一些好建议,如果您需要您要求的接口的不同实现在构造函数中,您可以使用 Ninject Factory. For more information you can refer to this 答案。