5

我们有一个用 ASP.NET MVC 编写的项目,我们使用 NInject 将存储库注入控制器。目前我们正在使用属性和 Inject-attribute 来注入存储库,效果很好:

[Inject]
public IMyRepository MyRepos {get;set;}

另一种注入方法是使用以下命令“手动”进行NInjectServiceLocator

var myRepos = NInjectServiceLocatorInstance.Resolve<IMyRepository>();

现在我想知道以下几点:第一种方法要求所有存储库都列在控制器的顶部(当然不一定在顶部,但它是最合乎逻辑的位置)。每当发出请求时,NInject 都会实例化每个存储库。无论在特定操作中是否确实需要所有存储库,都会发生这种情况。

使用第二种方法,您可以更精确地控制哪些存储库实际上是必需的,因此这可能会在创建控制器时节省一些开销。但是您可能还必须包含代码以在多个位置检索相同的存储库。

那么哪一个会更好呢?是只拥有一堆存储库属性更好,还是在需要它们的时间和地点解决特定操作实际必需的存储库更好?注入“无用”存储库是否涉及性能损失?那里有(甚至;-)更好的解决方案吗?

4

3 回答 3

3

我更喜欢构造函数注入:

private readonly IMyRepository _repository;

public MyController(IMyRepository repository)
{
    _repository = repository;
}
  • 您的所有依赖项都在一个操作中列出
  • 你的控制器不需要知道任何关于 NInject
  • 您可以通过将接口直接存根到构造函数来对控制器进行单元测试,而无需 NInjects 参与
  • 控制器有更简洁的代码

NInject 或任何其他 DI 框架将在幕后完成工作,让您专注于实际问题,而不是 DI。

于 2013-08-14T08:43:35.690 回答
2

Constructor Injection应该是您使用 DI 时的默认选择。

您应该问自己,控制器是否真的依赖于该特定类才能工作。

Method injection如果您只有需要依赖项的特定方法,也许也可以是特定场景的解决方案。

我从未使用过Property Injection,但 Mark Seeman 在他的书(.NET 中的依赖注入)中描述了它:

仅当您正在开发的类具有良好的 LOCAL DEFAULT 并且您仍希望使调用者能够提供类的 DEPENDENCY 的不同实现时,才应使用 PROPERTY INJECTION。

当 DEPENDENCY 是可选的时,最好使用 PROPERTY INJECTION。

注意 关于 PROPERTY INJECTION 是否表示可选依赖的问题存在一些争议。作为一般的 API 设计原则,我认为属性是可选的,因为您很容易忘记分配它们并且编译器不会抱怨。如果你在一般情况下接受这个原则,你也必须在 DI 的特殊情况下接受它。4

本地默认值描述为:

与使用者在同一程序集中定义的抽象的默认实现。

除非您正在构建 API,否则我建议不要使用属性注入

每当发出请求时,NInject 都会实例化每个存储库。无论在特定操作中是否确实需要所有存储库,都会发生这种情况。

我认为您在使用构造函数注入时不必太担心性能

于 2013-08-14T09:35:23.367 回答
0

到目前为止,我最喜欢的方法是:

public class MyController : Controller
{
    public IMyRepository MyRepos {get;set;}

    public MyController(IMyRepository repo)
    {
        MyRepos = repo;
    }
}

因此,您可以使用 NuGet 包,例如 Ninject.MVC3(或 MVC4),它特别支持在 MVC 自己的 IoC 类中包含 Ninject 内核

https://github.com/ninject/ninject.web.mvc/wiki/MVC3

一旦你加入了 Ninject 钩子,你就可以让它将实例注入到控制器的构造函数中,我认为这更干净。

编辑:

啊,好的。更彻底地阅读了您的问题后,我知道您将要解决的问题。简而言之,如果您想选择实例化哪些 repo 类,则需要手动调用,例如:

var myRepos = NInjectServiceLocatorInstance.Resolve<IMyRepository>();

您不能将 Ninject(或任何其他 IoC AFAIK)配置为基于当前执行方法有选择地创建对象实例。我觉得这种粒度级别是一个真正的边缘情况,可以通过编写自己的控制器工厂类来解决,但那将是矫枉过正。

于 2013-08-14T08:43:05.513 回答