将Nininject MVC与类库一起使用

Jam*_*ees 17 c# asp.net-mvc ninject ioc-container

我对IoC框架很陌生,所以请原谅术语.

所以我所拥有的是一个带有Nininject MVC参考的MVC项目.我的项目中有其他类libarys,例如Domain层,我希望能够在那里使用Ninject框架,但我的所有绑定都在MVC项目NinjectWebCommon.csApp_Start文件夹下:

private static void RegisterServices(IKernel kernel)
{
    kernel.Bind<IHardwareService>().To<WindowsHardwareService>();
    kernel.Bind<IStatusApi>().To<StatusApiController>();
}
Run Code Online (Sandbox Code Playgroud)

目前在我的类库中我使用构造函数注入,但有时我不得不对依赖项进行硬编码:

var service = new WindowsHardwareService();
Run Code Online (Sandbox Code Playgroud)

当我希望能够做到以下几点时:

IKernel kernel = new StandardKernel(.....);
var context = kernel.Get<IHardwareService>();
Run Code Online (Sandbox Code Playgroud)

我没有做以下因为我没有任何模块?我读过的所有文档主要针对的是常规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;
}
Run Code Online (Sandbox Code Playgroud)

IoCModules.cs(在Project.Ioc项目中)

public class IoCModules
{
    public IKernel GetKernel()
    {
        var modules = new CoreModule();
        return modules.Kernel;
    }
}
Run Code Online (Sandbox Code Playgroud)

CoreModule.cs(在Project.IoC.Modules项目中)< - 这是所有项目的所有引用,这是围绕任何循环依赖问题.

public class CoreModule : NinjectModule
{
    public override void Load()
    {
       Bind<IHardwareService>().To<WindowsHardwareService>();
       Bind<IStatusApi>().To<StatusApiController>();
    }
}
Run Code Online (Sandbox Code Playgroud)

但我现在得到以下内容:

激活IHardwareService时出错

没有匹配的绑定可用,并且该类型不可自绑定.激活路径:

2)将依赖IHardwareService注入到DashboardController类型的构造函数的参数服务中

1)请求DashboardController

建议:

1)确保您已为IHardwareService定义了绑定.

2)如果在模块中定义了绑定,请确保已将模块加载到内核中.

3)确保您没有意外创建多个内核.

4)如果使用构造函数参数,请确保参数名称与构造函数参数名称匹配.

5)如果使用自动模块加载,请确保搜索路径和过滤器正确无误.

kay*_*ess 19

看来你有很多问题需要在这里解答,所以我会努力做到最好.

根据您当前的问题,我将尝试"绘制"您当前实现的简化架构:

  • 域层:域的核心,业务实体的位置等.
  • 基础架构层:这是您的服务所在的位置,例如:WindowsHardwareService
    • 国际奥委会:我倾向于称之为DependencyResolution集会.
  • UI: MVC应用程序

假设这一切之上,我们可以说,您的应用程序Composition Root或者Entry pointUI MVC项目.使用a的一个主要概念DI Container是在Composition Root设置中将其初始化/在此处执行所有需要的绑定和注册.在入口点这样做的主要目的是避免Service Locator反模式.

通过使用一个DI Container你不这样做new()你的类实现或得到内核,而是要求注册的依赖,下面的规则Inversion Of Control或也被称为好莱坞原则.

在philosphy课程之后,我们终于可以实现一些实际的实现.

创建Ninject模块:在您的IOC程序集中,我们将此文件称为ServiceModule.cs

using Ninject.Modules;
public class ServiceModule : NinjectModule
{
    public override void Load()
    {
        Bind<IHardwareService>().To<WindowsHardwareService>();
        Bind<IStatusApi>().To<StatusApiController>();
    }
}
Run Code Online (Sandbox Code Playgroud)

这将是Ninject module您将注册/加载的Composition Root.

现在关于组合根:UI MVC项目中NinjectWebCommon.cs 您可以拥有一个负责加载模块的方法,如下所示.

private static void RegisterServices(IKernel kernel)
{
    var modules = new List<INinjectModule>
        {
            new ServiceModule()
            //, new FooModule()
            //, new BarModule()
        };

    kernel.Load(modules);
}  
Run Code Online (Sandbox Code Playgroud)

最后你DashboardControllerUI MVC:

public class DashboardController : Controller
{
    private readonly IHardwareService _hardwareService;

    public DashboardController(IHardwareService hardwareService)
    {
        _hardwareService = hardwareService;
    }
}
Run Code Online (Sandbox Code Playgroud)

此时,您要求IHardwareService在控制器构造函数中注册实现.该DI Container会做肮脏的工作,并通过你,你可以在你的控制器后的工作实例.

关于接口的注释:我倾向于将这些接口放入一个自己的程序集中,我只存储接口,例如:Project.Domain.Interfaces或者Project.Infrastructure.Interfaces每个程序集中只包含域或基础结构接口.

程序集之间的参考:

要将所有这些放在一起,UI只引用IOC程序集和接口程序集,它们包含您绑定的接口Ninject Module.

总结以上所有内容:

你自己的课程和界面只是DI容器在一起的部分.

希望我清理一下.

编辑:作为@AndreySarafanov在评论中指出的一些好建议,如果你需要在构造函数中要求的接口的不同实现,你可以使用Ninject Factory.有关更多信息,请参阅答案.

  • 我只想补充一点,当你需要在运行时创建对象时,最好将工厂添加为依赖项,这样你就不需要`Kernel.Get`.在简单的情况下,这些工厂可以自动实现(例如通过Ninject.Extensions.Factory). (2认同)