【问题标题】:Using Nininject MVC with class libraries将 Nininject MVC 与类库一起使用
【发布时间】:2016-02-19 23:58:53
【问题描述】:

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

所以我拥有的是一个带有 Nininject MVC 引用的 MVC 项目。 我的项目中有其他类库,例如领域层,我希望能够在其中使用 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 版本。

我需要做什么,如何在 MVC 版本中使用常规的 Ninject 库?

更新

这是我尝试过的:

这样做的目的是让每个项目都可以加载模块并获得当前注入的接口。

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>();
    }
}

但我目前得到以下信息:

激活 IHardwareService 时出错

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

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

1) DashboardController 的请求

建议:

1) 确保您已为 IHardwareService 定义绑定。

2) 如果绑定是在模块中定义的,请确保该模块已加载到内核中。

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

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

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

【问题讨论】:

  • see the following answer。我认为它达到了相似的点,会帮助你:)。
  • @Coulton 感谢您的建议,但它并没有真正回答,我不想使用属性注入,我能够将 Ninject MVC 与其他类库一起使用,这可能包括移动我的绑定到更“常见”的地方。
  • 好的,没问题。如果不是属性或构造函数注入,你想做什么样的注入?
  • 问题是关于如何为您自己的注册创建 ninject 模块以及从哪里放置和引用它们?
  • @kayess 是的,我不希望我的 UI 项目引用所有内容,因为我需要在其中添加绑定,我需要一个引用 Ninject 的“通用”项目才能使用它解决方案中的任何地方,同时保持 Ninject MVC 部分正常工作。

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


【解决方案1】:

看来你有很多问题需要在这里回答,所以我会尽力做到最好的。

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

  • 域层:域的核心、业务实体的位置等。
  • 基础设施层:这是您的服务所在的位置,例如:WindowsHardwareService
    • 国际奥委会:我倾向于将此称为DependencyResolution 大会。
  • 用户界面: MVC 应用程序

假设以上所有,我们可以声明您的应用程序Composition RootEntry pointUI 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>();
    }
}

这将是您将在Composition Root 中注册/加载的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;
    }
}

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

关于接口的注释:我倾向于将它们放入自己的程序集中,我只存储接口,例如:Project.Domain.InterfacesProject.Infrastructure.Interfaces 其中每个程序集都只包含域或基础设施接口。

程序集之间的引用:

为了将所有这些放在一起,UI 仅引用 IOC 程序集和包含您在 @987654349 中绑定的接口的 interfaces 程序集@。

总结以上所有内容:

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

希望我把它弄清了一点。

编辑:正如 @AndreySarafanov 在 cmets 中指出的一些好建议,如果您需要在构造函数中要求的接口的不同实现,您可以使用Ninject Factory。更多信息可以参考this解答。

【讨论】:

  • 是的,这很有意义,但我有一个问题,例如我不希望 UI 引用 SOC 的基础设施层。我试图创建 IOC 项目以在其中包含所有引用,并且 UI 将仅引用 IOC 项目。
  • 很好,但是我如何在其他项目中访问内核?做 Kernel.Get ?想一想,如果一切都抽象在一个接口后面并使用构造函数注入,我应该永远不需要kernel.Get&lt;T&gt; 对吧?
  • 是的,没错!您尝试并且从不做 kernel.Get,您在 Compostion Root 中组合您的对象图!
  • 我只是补充一点,如果您需要在运行时创建对象,最好将工厂添加为依赖项,这样您就不需要Kernel.Get。在简单的情况下,这些工厂可以自动实现(例如,通过 Ninject.Extensions.Factory)。
猜你喜欢
  • 1970-01-01
  • 2010-10-15
  • 1970-01-01
  • 2011-02-25
  • 2012-06-02
  • 2010-10-04
  • 2017-08-27
  • 2010-09-09
  • 2011-06-26
相关资源
最近更新 更多