将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) 如果使用的是自动模块加载,请确保搜索路径和筛选器正确无误。

将NininjectMVC与类库结合使用

你似乎有很多问题需要在这里回答,所以我会尽力。

基于您当前的问题,我将尝试"起草"您当前实现的简化架构:

  • 域层:域的核心、业务实体所在地等
  • 基础结构层:这是您的服务所在的位置,例如:WindowsHardwareService
    • IOC:我倾向于将其称为DependencyResolution程序集
  • UI:MVC应用程序

假设以上都是,我们可以声明您的应用程序Composition RootEntry pointUIMVC项目。使用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中的DashboardControllerMVC:

public class DashboardController : Controller
{
    private readonly IHardwareService _hardwareService;
    public DashboardController(IHardwareService hardwareService)
    {
        _hardwareService = hardwareService;
    }
}

此时,您需要在控制器构造函数中注册IHardwareService的实现。DI Container将完成肮脏的工作,并将稍后可以在控制器中使用的实例传递给您。

关于接口的注意事项:我倾向于将这些接口放入自己的程序集,在那里我只存储接口,例如:Project.Domain.InterfacesProject.Infrastructure.Interfaces,其中每个程序集只包含域或基础结构接口。

程序集之间的引用:

要将所有这些放在一起,UI仅引用IOC程序集和包含您在Ninject Module中绑定的接口的接口组件。

总结以上所有内容:

您的类和接口本身只是DI容器将粘合在一起的部分。

希望我能澄清一下。

EDIT:正如@AndreySarafanov在评论中指出的一些好建议,如果你需要在构造函数中要求的接口的不同实现,你可以使用NinjectFactory。有关更多信息,您可以参考此答案。