I’ve been hearing about dependency injection for quite a while now, and I figured it was about time for me to figure out what all the hype was about.
I decided I probably needed some more background on the subject before I got started with it, so I watched a video by Bob Lee that served as an introduction to the dependency injection framework for Java put together by Google called Guice.
After seeing that video, and reading an interesting article and discussion about the topic, I decided it was time for me to jump right in. I’m going to use a new DI framework for .NET called Ninject to figure out how dependency injection works, and how it could be useful for me.
The only good way to get started was to download it and try it, so it was off to http://svn.ninject.org/trunk to download the latest build from the subversion repository. Now that I have the library, I needed to come up with some sort of small project that I could create to test the dependency injection pattern. I decided to create a time tracking system where I could log hours on projects, keep track of clients, etc.
The first thing I have to do is come up with the basic architecture for my project, and then figure out how to best use dependency injection to accomplish my goals. After thinking about the things I wanted to do with my time tracking application, I fired up Visual Studio and started laying out the architecture. From a solution standpoint, I broke up the application into several projects. The first one was a class library that I called TimeTracker.Model. This library is going to hold the definition for all of my entities, and the class diagram looks like this: (for now)
The next project in the solution is a collection of all of the services and / or interfaces that I am going to need. This is where I begin to see where dependency injection is going to start to pay off. My thought right now is that I want to have some sort of service that stores this information in a database, but I don’t really want to write that part now. I’m going to write a mock service that will be derived from the same interface to allow me to work on the UI and repository without creating the database tables yet. I can just inject the repository model that I want and let Ninject figure out what I’m trying to do. At this point I have 2 services that both implent my IRepository interface, as shown here:
I haven’t implemented anything yet on the DBRepository, I’m going to use the MockRepository to get the UI figured out without having to worry about writing stored procedures, creating and updating database tables, etc.
The third project I have in my solution is called TimeTracker.Shell. This is where the Ninject kernel is going to be wired up, and where I define my injection bindings. I also have a project called TimeTracker.UI which will contain all of my forms, user controls, etc. I could have probably combined these into one project, but I decided to split them up. This is where I start getting into dependency injection and the Ninject framework. The first thing I had to do was create a module where I could define my bindings. When I set up my module, I extended the StandardModule type, as shown here.
I am trying to keep all of my NInject modules, etc in my shell. That way it is easier to make changes later should my requirements change. The binding above is binding my repository to my mock repository. This binding is what I am going to change after I add my database repository. After I have my binding set up, I need to create a form in my UI. This will be the form that starts up with the application. When I set up my form, the important thing here is to create a constructor that takes an IRepository type, and tag it with the NInject attribute [Inject], which is defined in the Ninject.Core .dll. To keep the designer happy, I also kept the default constructor too. My form looks like this:
Now I can use the _repository variable in my form, and it won’t matter if it’s using a mock service, a database service, or whatever. The UI code will not have to change at all. I understand that Ninject will also recursively solve dependencies, which is sweet. This means that if my repository had dependencies, they would be injected automatically for me here.
We’re missing one part now, I need the shell to start up my main form, and I also need to link up the module I created with the Ninject kernel. This happens in Main() function located in the shell project. My main function now looks like this:
At this point, I can use the _repository variable defined in my form, and Ninject will give me a MockRepository implementation, since that is the binding I set up. This has been a very rudimentary look at dependency injection, specifically the Ninject framework. I’m beginning to see the value that dependency injection provides, and I will continue to explore these ideas as this project continues. Stay tuned! I’ll post another article when I get further along.