将Nininject MVC与类库一起使用

时间:2015-11-18 09:57:47

标签: c# asp.net-mvc ninject ioc-container

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

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

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 / 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项目中)&lt; - 这是所有项目的所有引用所在,这可以解决任何循环依赖问题。

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

1 个答案:

答案 0 :(得分:19)

您似乎有很多问题需要在这里解答,所以我会尽力做到最好。

根据您当前的问题,我将尝试“制定”您当前实施的简化架构:

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

假设上述所有情况,我们可以声明您的应用Composition RootEntry point UI MVC项目。使用DI Container的主要概念之一是您在Composition Root设置/在此处执行所有需要的绑定和注册。在入口点执行此操作的主要目的是避免使用Service Locator反模式。

使用DI Container你没有new()你的类实现或获取内核而是要求注册的依赖项,遵循Inversion Of Control的规则或者也称为好莱坞原则。

在哲学课程之后,我们终于可以实现一些实际的实施。

IOC 程序集中创建Ninject module ,我们可以将此文件称为ServiceModule.cs

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

这将是您在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);
}  

最后是 UI MVC中的DashboardController

public class DashboardController : Controller
{
    private readonly IHardwareService _hardwareService;

    public DashboardController(IHardwareService hardwareService)
    {
        _hardwareService = hardwareService;
    }
}

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

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

程序集之间的引用:

要将所有这些放在一起, UI 仅引用 IOC 程序集和接口程序集,其中包含您绑定在{{{ 1}}。

总结以上所有内容:

你自己的类和接口只是DI容器一起粘合的部分。

希望我清理一下。

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