2012-01-13 40 views
18

我一直在尝试使用Ninject,并有几个问题。首先,我是否需要在所有我想使用注入的构造函数上使用Inject属性。这似乎是一个非常蹩脚的设计?我是否需要创建一个内核,然后在注入的类中传递所有内容?如何使用Ninject

回答

22

First of all do I need to use the Inject attribute on all constructors that I want to use injection for. This seems like a really lame design?

不,你根本不应该这样做。由于您使用ASP.NET MVC,因此您只需安装Ninject.MVC3 Nuget包。这会让你从App_Start文件夹中的NinjectMVC3类开始。您可以使用RegisterServices方法向Ninject注册您的接口/类。所有对这些接口具有依赖关系的控制器将由Ninject自动解析,不需要Inject属性。

Do I need to create a Kernel then use that everywhere I pass in an injected class?

否 - 你所描述听起来更像是在Service Locator pattern什么,而不是依赖注入 - 你会想,而不是使用内核特定的类内解决他们在你的依赖最好通过在构造函数中。应该只有一个中心组合根,在这里完成解析,它位于上面提到的RegisterServices方法中的组合根内,或者在那里实例化一个单独的Ninject模块 - 后面的方法将允许您更灵活一些和模块化(无双关旨在)改变你如何解决你的依赖关系。

这是一个很好的beginner's tutorial on dependency injection with Ninject and MVC3

+0

感谢您的信息。我现在已经移除了[Inject]属性。我看了一个教程视频,这是我学会这样做的地方。我现在需要做的是将参数传递给已使用WithConstructorArgument的已解析concreate类,但仍然出现此错误:没有为此对象定义无参数构造函数。 – 2012-01-13 16:42:03

+0

另外,我现在很困惑,你发布的链接也使用StandardKerbal方法。我对DI的理解是,容器自动解决依赖关系(取决于您设置的绑定)。 – 2012-01-13 16:44:53

+0

@Sachi:如果需要传递的参数也用Ninject解析,你不需要'WithConstructorArgument()' - 把它想象成一张图 – BrokenGlass 2012-01-13 16:47:52

58

开始使用Ninject的最佳方法是从小处着手。寻找new

在应用程序中间的某个位置,您正在另一个类中创建一个类。这意味着你正在创建一个依赖项。依赖注入约传入那些依赖关系,通常通过构造函数,而不是嵌入他们。

假设你有一个这样的班级,用于在Word中自动创建特定类型的笔记。 (这类似于一个项目,我一直在做的工作最近。)

class NoteCreator 
{ 
    public NoteHost Create() 
    { 
     var docCreator = new WordDocumentCreator(); 
     docCreator.CreateNewDocument(); 
     [etc.] 

WordDocumentCreator是处理建立在Microsoft Word中一个新的文档(创建Word实例等)的具体的类。我的课程NoteCreator,取决于WordDocumentCreator以执行其工作。

问题是,如果有一天我们决定转移到一个优秀的文字处理器,我必须去查找WordDocumentCreator实例化的所有地方,并将它们改为实例化WordPerfectDocumentCreator

现在想象一下,我改变我的课看起来像这样:

class NoteCreator 
{ 
    WordDocumentCreator docCreator; 

    public NoteCreator(WordDocumentCreator docCreator) // constructor injection 
    { 
     this.docCreator = docCreator; 
    } 

    public NoteHost Create() 
    { 
     docCreator.CreateNewDocument(); 
     [etc.] 

我的代码并没有发生太大的变化;我在Create方法中完成的所有操作都是使用new删除该行。但现在我正在注入我的依赖。让我们做一个更小的变化:

class NoteCreator 
{ 
    IDocumentCreator docCreator; 

    public NoteCreator(IDocumentCreator docCreator) // change to interface 
    { 
     this.docCreator = docCreator; 
    } 

    public NoteHost Create() 
    { 
     docCreator.CreateNewDocument(); 
     [etc.] 

而是传递一个混凝土WordDocumentCreator的,我已经提取的IDocumentCreator接口CreateNewDocument方法。现在我可以通过任何类实现该接口,并且所有NoteCreator所要做的就是调用它所知道的方法。

现在棘手的部分。我现在应该在我的应用程序中出现编译错误,因为我正在创建NoteCreator的一个无参数构造函数,它不再存在。现在我需要拉出依赖关系。换句话说,我会通过与上面的相同的过程,但现在我将它应用到创建新的NoteCreator的类。当你开始提取依赖关系时,你会发现它们往往会“冒泡”到你的应用程序的根目录,这就是只有的地方你应该有一个对你的DI容器的引用(例如Ninject)。

我需要做的另一件事是配置Ninject。的关键一环是一类,看起来像这样:

class MyAppModule : NinjectModule 
{ 
    public override void Load() 
    { 
     Bind<IDocumentCreator>() 
      .To<WordDocumentCreator>(); 

这告诉Ninject,当我试图创建一个类,上下行的地方,需要一个IDocumentCreator,它应该创建一个WordDocumentCreator并使用它。 Ninject的过程如下所示:

  • 创建应用程序的MainWindow。它的构造函数需要NoteCreator
  • 好吧,创建一个NoteCreator。但是构造函数需要IDocumentCreator
  • 我的配置说对于IDocumentCreator,我应该使用WordDocumentCreator。所以创建一个WordDocumentCreator
  • 现在我可以将WordDocumentCreator传递给NoteCreator。
  • 现在我可以将NoteCreator传递给MainWindow

这个系统的美是三倍的。首先,如果你未能配置某些东西,你马上就会知道,因为你的对象是在你的应用程序运行后立即创建的。 Ninject会给你一个有用的错误消息,说你的IDocumentCreator(例如)不能解决。

其次,如果管理后强制要求上级字处理器的用户,所有你需要做的就是

  • WordPerfectDocumentCreator实现IDocumentCreator
  • 改变MyAppModule以上,改为绑定IDocumentCreator改为WordPerfectDocumentCreator

第三,如果我想测试我NoteCreator,我没有在真正WordDocumentCreator(或我使用等等)来传递。我可以通过一个假一个。这样我可以写一个测试假设我的IDocumentCreator工作正常,只测试NoteCreator本身的运动部件。我的假IDocumentCreator将不会做任何事情,但返回正确的答案,我的测试将确保NoteCreator做正确的事情。

有关如何以这种方式构建应用程序的更多信息,请参阅Mark Seemann最近出版的书籍Dependency Injection in .NET。不幸的是,它并不包含Ninject,但它确实涵盖了许多其他的DI框架,并且讨论了如何以上述方式构建应用程序。

也可以看看Michael Feathers的Working Effectively With Legacy Code。他谈到了上述的测试方面:如何分离接口并传递假货以隔离行为并使其处于测试中。

+4

对于依赖注入和Ninject都是非常好的解释!谢谢,我将它复制到我的Evernote以作进一步参考。 – Tarik 2013-03-01 22:00:24

+0

@Kyralessa这真是一个很好的解释。迄今为止我所读过的最好的一本,清晰而且清晰。你在开始做什么被称为穷人的依赖注射? – 2014-03-04 07:38:11

+0

迄今为止我见过的最好的解释给这个人一个土豆。 +1 – 2015-07-25 16:33:52

7

不要忘记有文档,其中包括一个介绍,我觉得这是非常合适的考虑到你问的那种问题on the Ninject Wiki。如果您尝试使用Ninject而不读取它,您只会烦恼自己。

table of contents贴在您的书签栏上一会儿。

我也强烈建议Mark SeemannDependency Injection in .Net作为基于DI的体系结构的配套书(尽管它不直接覆盖Ninject)。