将NininjectMVC与类库结合使用
本文关键字:结合 类库 NininjectMVC | 更新日期: 2023-09-27 18:22:18
我对IoC框架还很陌生,所以请原谅这个术语。
所以我有一个MVC项目,它引用了NininjectMVC。我的项目中还有其他类库,例如Domain层,我希望能够在其中使用Ninject框架,但我的所有绑定都在MVC项目中App_Start
文件夹下的NinjectWebCommon.cs
中:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IHardwareService>().To<WindowsHardwareService>();
kernel.Bind<IStatusApi>().To<StatusApiController>();
}
目前在我的类库中,我使用构造函数注入,但有时我不得不对依赖项进行硬编码:
var service = new WindowsHardwareService();
当我想能够做到以下几点:
IKernel kernel = new StandardKernel(.....);
var context = kernel.Get<IHardwareService>();
我没有做以下事情,因为我没有任何模块?我读过的所有文档主要针对常规的Ninject库,而不是MVC版本。
我需要做什么,以及如何将常规的Ninject库与MVC版本一起使用?
更新
这就是我尝试过的:
这样做的目的是让每个项目都可以加载模块并获得当前注入的接口。
App_Start/NjectWebCommon.cs(在MVC项目中)
private static void RegisterServices(IKernel kernel)
{
var modules = new IoCModules();
var newKernal = modules.GetKernel();
kernel = newKernal;
}
IoCModules.cs(In-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>();
}
}
但我目前得到的是:
激活IHardwareService 时出错
没有匹配的绑定可用,并且该类型不可自绑定。激活路径:
2) 将依赖项IHardwareService注入DashboardController 类型构造函数的参数服务
1) 请求DashboardController
建议:
1) 请确保您已为IHardwareService定义了绑定。
2) 如果绑定是在模块中定义的,请确保该模块已加载到内核中。
3) 请确保您没有意外创建多个内核。
4) 如果使用构造函数参数,请确保参数名称与构造函数参数名称匹配。
5) 如果使用的是自动模块加载,请确保搜索路径和筛选器正确无误。
你似乎有很多问题需要在这里回答,所以我会尽力。
基于您当前的问题,我将尝试"起草"您当前实现的简化架构:
- 域层:域的核心、业务实体所在地等
-
基础结构层:这是您的服务所在的位置,例如:
WindowsHardwareService
- IOC:我倾向于将其称为
DependencyResolution
程序集
- IOC:我倾向于将其称为
- UI:MVC应用程序
假设以上都是,我们可以声明您的应用程序Composition Root
或Entry point
是UIMVC项目。使用DI Container
的主要概念之一是在Composition Root
中初始化它,在此处设置/执行所有需要的绑定和注册。在切入点中这样做的主要意图是避免Service Locator
反模式。
通过使用DI Container
,您不会new()
升级类实现或获得内核,而是按照Inversion Of Control
的规则或也称为Hollywood原则要求注册依赖项。
在哲学课程之后,我们终于可以得到一些实际的实施。
在IOC程序集中创建一个Ninject模块:,让我们将此文件称为ServiceModule.cs
using Ninject.Modules;
public class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<IHardwareService>().To<WindowsHardwareService>();
Bind<IStatusApi>().To<StatusApiController>();
}
}
这将是您将在Composition Root
中注册/加载的Ninject module
。
现在关于Composition Root:在UIMVC项目NinjectWebCommon.cs
中您可以有一个负责加载模块的方法,如下所示。
private static void RegisterServices(IKernel kernel)
{
var modules = new List<INinjectModule>
{
new ServiceModule()
//, new FooModule()
//, new BarModule()
};
kernel.Load(modules);
}
最后是UI中的DashboardController
MVC:
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
中绑定的接口的接口组件。
总结以上所有内容:
您的类和接口本身只是DI容器将粘合在一起的部分。
希望我能澄清一下。
EDIT:正如@AndreySarafanov在评论中指出的一些好建议,如果你需要在构造函数中要求的接口的不同实现,你可以使用NinjectFactory。有关更多信息,您可以参考此答案。