如何使用 Ninject
我今天一直在尝试使用 Ninject,并有几个问题。首先,我是否需要在所有想要使用注入的构造函数上使用 Inject 属性。这似乎是一个非常蹩脚的设计?我是否需要创建一个内核,然后在传入注入类的任何地方使用它?
I have been trying to use Ninject today and have a couple of questions. 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? Do I need to create a Kernel then use that everywhere I pass in an injected class?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
开始使用 Ninject 的最佳方法是从小事做起。寻找
新的
。在应用程序中间的某个位置,您正在另一个类中创建一个类。这意味着您正在创建依赖项。依赖注入是指通常通过构造函数传入这些依赖项,而不是嵌入它们。
假设您有一个这样的类,用于在 Word 中自动创建特定类型的注释。 (这与我最近在工作中完成的一个项目类似。)
WordDocumentCreator
是一个类,用于处理在 Microsoft Word 中创建新文档的细节(创建 Word 的实例等)。我的类NoteCreator
依赖WordDocumentCreator
来执行其工作。问题是,如果有一天我们决定转向更高级的文字处理程序,我必须找到所有实例化
WordDocumentCreator
的地方,并将它们更改为实例化WordPerfectDocumentCreator
。现在想象一下,我将我的类更改为如下所示:
我的代码没有改变那么多;我在
Create
方法中所做的就是删除带有new
的行。但现在我正在注入我的依赖。让我们再做一个小改动:我提取了一个
IDocumentCreator
接口,而不是传入具体WordDocumentCreator
使用CreateNewDocument
方法。现在我可以传入实现该接口的任何类,而NoteCreator
所要做的就是调用它知道的方法。现在是棘手的部分。现在,我的应用程序中应该出现编译错误,因为我在某个地方使用不再存在的无参数构造函数创建
NoteCreator
。现在我还需要删除该依赖项。换句话说,我经历了与上面相同的过程,但现在我将其应用到创建新NoteCreator
的类。当您开始提取依赖项时,您会发现它们往往会“冒泡”到应用程序的根目录,这是您应该引用 DI 容器的唯一位置(例如 Ninject )。我需要做的另一件事是配置 Ninject。最重要的部分是一个如下所示的类:
这告诉 Ninject,当我尝试创建一个需要
IDocumentCreator
的类时,它应该创建一个WordDocumentCreator
代码>并使用它。 Ninject 经历的过程如下所示:MainWindow
。它的构造函数需要一个NoteCreator
。IDocumentCreator
,我应该使用WordDocumentCreator
。因此,创建一个WordDocumentCreator
。WordDocumentCreator
传递给 NoteCreator。NoteCreator
传递给MainWindow
。这个系统的优点有三个。
首先,如果您未能配置某些内容,您会立即知道,因为您的对象是在应用程序运行后立即创建的。 Ninject 会给您一条有用的错误消息,指出您的
IDocumentCreator
(例如)无法解析。其次,如果管理层稍后要求用户使用高级文字处理程序,那么您所要做的就是
IDocumentCreator
的WordPerfectDocumentCreator
。MyAppModule
,将IDocumentCreator
绑定到WordPerfectDocumentCreator
。第三,如果我想测试我的
NoteCreator
,我不必传入 realWordDocumentCreator
(或我正在使用的任何东西) 。我可以传递一个假。这样我就可以编写一个测试,假设我的IDocumentCreator
工作正常,并且只测试NoteCreator
本身的移动部分。我的假IDocumentCreator
除了返回正确的响应之外什么也不做,我的测试将确保NoteCreator
做正确的事情。有关如何以这种方式构建应用程序的更多信息,请参阅 Mark Seemann 最近的书 .NET 中的依赖注入。不幸的是,它没有涵盖 Ninject,但它确实涵盖了许多其他 DI 框架,并且讨论了如何按照我上面描述的方式构建应用程序。
另请参阅 Michael Feathers 撰写的有效使用旧代码。他谈到了上面的测试方面:如何打破接口并传入伪造品以隔离行为并对其进行测试。
The best way to get started with Ninject is to start small. Look for a
new
.Somewhere in the middle of your application, you're creating a class inside another class. That means you're creating a dependency. Dependency Injection is about passing in those dependencies, usually through the constructor, instead of embedding them.
Say you have a class like this, used to automatically create a specific type of note in Word. (This is similar to a project I've done at work recently.)
WordDocumentCreator
is a class that handles the specifics of creating a new document in Microsoft Word (create an instance of Word, etc.). My class,NoteCreator
, depends onWordDocumentCreator
to perform its work.The trouble is, if someday we decide to move to a superior word processor, I have to go find all the places where
WordDocumentCreator
is instantiated and change them to instantiateWordPerfectDocumentCreator
instead.Now imagine that I change my class to look like this:
My code hasn't changed that much; all I've done within the
Create
method is remove the line with thenew
. But now I'm injecting my dependency. Let's make one more small change:Instead of passing in a concrete
WordDocumentCreator
, I've extracted anIDocumentCreator
interface with aCreateNewDocument
method. Now I can pass in any class that implements that interface, and allNoteCreator
has to do is call the method it knows about.Now the tricky part. I should now have a compile error in my app, because somewhere I was creating
NoteCreator
with a parameterless constructor that no longer exists. Now I need to pull out that dependency as well. In other words, I go through the same process as above, but now I'm applying it to the class that creates a newNoteCreator
. When you start extracting dependencies, you'll find that they tend to "bubble up" to the root of your application, which is the only place where you should have a reference to your DI container (e.g. Ninject).The other thing I need to do is configure Ninject. The essential piece is a class that looks like this:
This tells Ninject that when I attempt to create a class that, somewhere down the line, requires an
IDocumentCreator
, it should create aWordDocumentCreator
and use that. The process Ninject goes through looks something like this:MainWindow
. Its constructor requires aNoteCreator
.IDocumentCreator
.IDocumentCreator
, I should useWordDocumentCreator
. So create aWordDocumentCreator
.WordDocumentCreator
to the NoteCreator.NoteCreator
to theMainWindow
.The beauty of this system is threefold.
First, if you fail to configure something, you'll know right away, because your objects are created as soon as your application is run. Ninject will give you a helpful error message saying that your
IDocumentCreator
(for instance) can't be resolved.Second, if management later mandates the user of a superior word processor, all you have to do is
WordPerfectDocumentCreator
that implementsIDocumentCreator
.MyAppModule
above, bindingIDocumentCreator
toWordPerfectDocumentCreator
instead.Third, if I want to test my
NoteCreator
, I don't have to pass in a realWordDocumentCreator
(or whatever I'm using). I can pass in a fake one. That way I can write a test that assumes myIDocumentCreator
works correctly, and only tests the moving parts inNoteCreator
itself. My fakeIDocumentCreator
will do nothing but return the correct response, and my test will make sure thatNoteCreator
does the right thing.For more information about how to structure your applications this way, have a look at Mark Seemann's recent book, Dependency Injection in .NET. Unfortunately, it doesn't cover Ninject, but it does cover a number of other DI frameworks, and it talks about how to structure your application in the way I've described above.
Also have a look at Working Effectively With Legacy Code, by Michael Feathers. He talks about the testing side of the above: how to break out interfaces and pass in fakes for the purpose of isolating behavior and getting it under test.
不,实际上您根本不必这样做。由于您使用 ASP.NET MVC,因此只需安装 Ninject.MVC3 Nuget 包即可。这将使您开始使用 App_Start 文件夹中的
NinjectMVC3
类。您可以使用RegisterServices
方法向 Ninject 注册您的接口/类。所有与这些接口有依赖关系的控制器将由 Ninject 自动解析,不需要 Inject 属性。不 - 您所描述的听起来更像 服务定位器模式,而不是依赖项注入 - 您需要传递依赖项理想情况下,在构造函数中,而不是使用内核在特定类中解析它们。应该只有一个完成解析的中央组合根,它位于上面提到的 RegisterServices 方法中的组合根内,或者在那里实例化一个单独的 Ninject 模块 - 后一种方法将允许您在改变解决依赖关系的方式方面具有更大的灵活性和模块化性(没有双关语)。
这是一个很好的关于使用 Ninject 和 MVC3 进行依赖注入的初学者教程。
No you shouldn't have to do this at all actually. Since you work with ASP.NET MVC you can just install the Ninject.MVC3 Nuget package. This will get you started with a
NinjectMVC3
class in the App_Start folder. You can use theRegisterServices
method to register your interfaces/classes with Ninject. All controllers that have dependencies to those interfaces will then be automatically resolved by Ninject, there is no need for the Inject attribute.No - what you are describing sounds more like the Service Locator pattern, not dependency injection - you will want to pass in your dependencies ideally in the constructor, instead of resolving them within particular classes using the kernel. There should be just one central composition root where the resolving is done, which is within the composition root in either the
RegisterServices
method mentioned above or a separate Ninject module instantiated there - the later approach will allow you a little more flexibility and modularity (no pun intended) in changing how you resolve your dependencies.Here's a good beginner's tutorial on dependency injection with Ninject and MVC3.
不要忘记有文档,包括一个介绍,考虑到您提出的问题,我认为这是非常合适的 在 Ninject Wiki 上。如果您在没有从头到尾阅读 Ninject 的情况下尝试使用 Ninject,那么您只是在烦恼自己。
将目录放在书签栏上一段时间。
我还强烈推荐 Mark Seemann 的 Dependency Injection in .Net 作为基于 DI 的架构的姊妹书(尽管它不直接涵盖 Ninject)。
Don't forget there are docs, including an intro I feel would be very appropriate given the sort of questions you are asking on the Ninject Wiki. You're just annoying yourself if you're trying to use Ninject without reading it end to end.
Stick the table of contents on your bookmark bar for a bit.
I can also highly recommend Mark Seemann's Dependency Injection in .Net as a companion book for DI based architecture (even though it doesnt directly cover Ninject).