22

I'm looking to implement dependency injection in a relatively large application but have no experience in it. I studied the concept and a few implementations of IoC and dependency injectors available, like Unity and Ninject. However, there is one thing which is eluding me. How should I organize instance creation in my application?

What I'm thinking about is that I can create a few specific factories which will contain logic of creating objects for a few specific class types. Basically a static class with a method invoking Ninject Get() method of a static kernel instance in this class.

Will it be a correct approach of implementing dependency injection in my application or should I implement it according to some other principle?

  • 5
    I do not think that there is the right way, but many right ways, depending on your project. I'd adhere to the others and suggest constructor injection, since you'll be able to make sure that every dependency is injected on one single point. Plus, if the constructor signatures grow too long, you'll know that the classes do too much. – Paul Kertscher Jun 27 '16 at 8:49
  • It's difficult to answer without knowing what sort of .net project you are building. A good answer for WPF might be a bad answer for MVC, for example. – JMK Jun 27 '16 at 13:51
  • Its nice to organize all the dependency registrations into a DI module for the solution or for each project, and possibly one for some tests depending on deeply you want to test. Oh yeah, of course you should use constructor injection, the other stuff is for more advanced/crazy usages. – Mark Rogers Jun 27 '16 at 18:46
30

Don't think yet about the tool that you are going to use. You can do DI without an IoC Container.

First point: Mark Seemann has a very good book about DI in .Net

Second: composition root. Make sure that the whole set up is done on the entry point of the project. Rest of your code should know about injections, not about any tool that is being used.

Third: Constructor Injection is the most likely way to go (there are cases in which you wouldn't want it, but not that many).

Fourth: look into using lambda factories and other similar features to avoid creating unneeded interfaces/classes for the sole purpose of injection.

  • 5
    All excellent advice; especially the first part: learn how to do pure DI, and then start looking at IoC containers that may reduce the amount of boilerplate code required by that approach. – David Arno Jun 27 '16 at 7:32
  • 6
    ...or skip IoC containers all together - to keep all the benefits of static verification. – Den Jun 27 '16 at 8:24
  • I like this advice is a good starting point, before getting into DI, and I actually have the Mark Seemann book. – Snoop Jun 27 '16 at 10:24
  • I can second this answer. We successfully used poor-mans-DI (hand-written bootstrapper) in a quite big application by tearing up parts of the bootstrapper logic into the modules that composed the application. – wigy Jun 27 '16 at 15:10
  • 1
    Be careful. Using lambda injections can be a fast track to madness, especially of the test-induced design damage kind. I know. I've gone down that path. – jpmc26 Jun 27 '16 at 15:26
13

There are two parts to your question - how to implement DI properly, and how to refactor a large application to use DI.

The first part is answered well by @Miyamoto Akira (especially the recommendation to read Mark Seemann's "dependency injection in .net" book. Marks blog is also a good free resource.

The second part is a good deal more complicated.

A good first step would be to simply move all instantiation into the classes constructors - not injecting the dependancies, just making sure you only call new in the constructor.

This will highlight all the SRP violations your have been making, so you can start breaking the class down into smaller collaborators.

The next issue you will find will be classes that rely on runtime parameters for construction. You can usually fix this by creating simple factories, often with Func<param,type>, initializing them in the constructor and calling them in the methods.

Next step would be to create interfaces for your dependancies, and add a second constructor to your classes that except these interfaces. Your parameterless constructor would new up the concrete instances and pass them to the new constructor. This is commonly called 'B*stard Injection' or 'Poor mans DI'.

This will give you the ability to do some unit testing, and if that was the main goal of the refactor, may be where you stop. New code will be written with constructor injection, but your old code can continue to work as written but still be testable.

You can of course go further. If you intend to use an IOC container, then a next step might be to replace all the direct calls to new in your parameterless constructors with static calls to the IOC container, essentially (ab)using it as a service locator.

This will throw up more cases of runtime constructor parameters to deal with as before.

Once this is done you can start to remove the parameterless constructors, and refactor to pure DI.

Ultimately this is going to be a lot of work, so make sure you decide why you want to do it, and prioritze the parts of the codebase that will benefit the most from the refactor

  • 3
    Thanks for a very elaborate answer. You gave me a few ideas on how to approach the issue I'm facing. The entire architecture of the app is already built with IoC in mind. The main reason I want to use DI is not even unit testing, it comes as a bonus but rather an ability to swap different implementations for different interfaces, defined in the core of my application, with as little effort as possible. The application in question works in a constantly changing environment and I often have to swap parts of the application to use new implementations according to changes in the environment. – user3223738 Jun 27 '16 at 10:13
  • 1
    Glad i could help, and yes i agree that the biggest advantage of DI is loose coupling and the ability to reconfigure easily that this brings, with unit testing being a nice side effect. – Steve Jun 27 '16 at 10:24
1

First I want to mention that you are making this significantly harder on yourself by refactoring an existing project rather than starting a new project.

You said it is a large application, so pick a small component to start with. Preferably a 'leaf-node' component that is not used by anything else. I don't know what the state of the automated testing is on this application, but you will be breaking all of the unit tests for this component. So be prepared for that. Step 0 is writing integration tests for the component you will be modifying if they don't exist already. As a last resort (no test infrastructure; no buy-in for writing it), figure out a series of manual tests you can do that verify this component is working.

The simplest way to state your goal for the DI refactor is that you want to remove all instances of the 'new' operator from this component. These generally fall into two categories:

  1. Invariant member variable: These are variables that are set once (typically in the constructor) and are not reassigned for the lifetime of the object. For these you can inject an instance of the object into the constructor. You are generally not responsible for disposing these objects (I don't want to say never here, but you really should not have that responsibility).

  2. Variant member variable / method variable: These are variables that will get garbage collected at some point during the lifetime of the object. For these, you'll want to inject a factory into your class to provide these instances. You are responsible for disposing objects created by a factory.

Your IoC container (ninject it sounds like) will take responsibility for instantiating those objects and implementing your factory interfaces. Whatever is using the component you've modified will need to know about the IoC container so it can retrieve your component.

Once you've completed the above, you will be able to reap whatever benefits you are hoping to get from DI in your selected component. Now would be a good time to add/fix those unit tests. If there were existing unit tests you'll have to make a decision about whether you want to patch them together by injecting real objects or write new unit tests using mocks.

'Simply' repeat the above for each component of your application, moving the reference to the IoC container up as you go until only main needs to know about it.

  • 1
    Good advice: start with a small component rather than the 'BIG re-write' – Daniel Hollinrake Jun 29 '16 at 10:49
0

Correct approach is to use constructor injection, if you use

What I'm thinking about is that I can create a few specific factories which will contain logic of creating objects for a few specific class types. Basically a static class with a method invoking Ninject Get() method of a static kernel instance in this class.

then you end up with service locator, than dependency injection.

  • Sure. Constructor injection. Let's say I have a class which is accepting an interface implementation as one of the arguments. But I still need to create an instance of the interface implementation and pass it to this constructor somewhere. Preferably it should be some centralized piece of code. – user3223738 Jun 27 '16 at 7:16
  • 2
    No, when you initialize the the DI container, you have to specify the implementation of interfaces, and DI container will create the instance and inject to the constructor. – Low Flying Pelican Jun 27 '16 at 7:35
  • Personally, I find constructor injection to be overused. I've seen it way too often that 10 different services are injected and only one is actually needed for a function call - why isn't that part of the function argument then? – urbanhusky Jun 27 '16 at 7:40
  • 2
    If 10 different services are injected, it's because someone is violating SRP, which should be split into smaller components. – Low Flying Pelican Jun 27 '16 at 7:51
  • 1
    @Fabio The question is what that would buy you. I've yet to see an example where having a giant class that deals with a dozen totally different things is a good design. The only thing DI does is make all those violations more obvious. – Voo Jun 27 '16 at 16:48
0

You say you want to use it but don't state why.

DI is nothing more than providing a mechanism for generating concretions from interfaces.

This in itself comes from the DIP. If your code is already written in this style and you have a single place where concretions are generated, DI brings nothing more to the party. Adding DI framework code here would simply bloat out and obfuscate your code base.

Assuming you do want to use it, you typically set up the factory/builder/container (or whatever) early in the application so it is clearly visible.

N.B. it is very easy to roll your own should you wish rather than commit to Ninject/StructureMap or whatever. If however you have a reasonable turnover of staff it may grease the wheels to use a recognised framework or at least write it in that style so that it isn't too much of a learning curve.

0

Actually, the "right" way is to NOT use a factory at all unless there is absolutely no other choice (as in unit testing and certain mocks - for production code you do NOT use a factory)! Doing so is actually an anti-pattern and should be avoided at all costs. The whole point behind a DI container is to allow the gadget to do the work for you.

As was stated above in a prior post, you want your IoC gadget to assume the responsibility for the creation of the various dependent objects in your app. That means letting your DI gadget create and manage the various instances itself. This is the whole point behind DI - your objects should NEVER know how to create and/or manage the objects that they depend on. To do otherwise breaks loose coupling.

Converting an existing application to all DI is a huge step, but setting aside the obvious difficulties in doing so, you will want also (just to make your life a bit easier) to explore a DI tool that will perform the bulk of your bindings automatically (the core to something like Ninject is the "kernel.Bind<someInterface>().To<someConcreteClass>()" calls that you make to match your interface declarations to those concrete classes you wish to use to implement those interfaces. It's those "Bind" calls that allow your DI gadget to intercept your constructor calls and provide the necessary dependent object instances. A typical constructor (pseudo code shown here) for some class might be:

public class SomeClass
{
  private ISomeClassA _ClassA;
  private ISomeOtherClassB _ClassB;

  public SomeClass(ISomeClassA aInstanceOfA, ISomeOtherClassB aInstanceOfB)
  {
    if (aInstanceOfA == null)
      throw new NullArgumentException();
    if (aInstanceOfB == null)
      throw new NullArgumentException();
    _ClassA = aInstanceOfA;
    _ClassB = aInstanceOfB;
  }

  public void DoSomething()
  {
    _ClassA.PerformSomeAction();
    _ClassB.PerformSomeOtherActionUsingTheInstanceOfClassA(_ClassA);
  }
}

Note that nowhere in that code was any code that created/managed/released either the instance of SomeConcreteClassA or of SomeOtherConcreteClassB. As a matter of fact, neither concrete class was even referenced. So...where did the magic happen?

In the start up portion of your app, the following took place (again, this is pseudo code but it's pretty close to the real (Ninject) thing...):

public void StartUp()
{
  kernel.Bind<ISomeClassA>().To<SomeConcreteClassA>();
  kernel.Bind<ISomeOtherClassB>().To<SomeOtherConcreteClassB>();
}

That little bit of code there tells the Ninject gadget to look for constructors, scan them, look for instances of interfaces that it has been configured to handle (that's the "Bind" calls) and then create and substitute an instance of the concrete class wherever the instance is referenced.

There is a nice tool that complements Ninject very well called Ninject.Extensions.Conventions (yet another NuGet package) that will do the bulk of this work for you. Not to take away from the excellent learning experience you will go through as you build this up yourself, but to get yourself started, this might be a tool to investigate.

If memory serves, Unity (formally from Microsoft now an Open Source project) has a method call or two that do the same thing, other tools have similar helpers.

Whatever path you choose, definitely read Mark Seemann's book for the bulk of your DI training, however, it should be pointed out that even the "Great Ones" of the software engineering world (like Mark) can make glaring errors - Mark forgot all about Ninject in his book so here is another resource written just for Ninject. I have it and its a good read: Mastering Ninject for Dependency Injection

0

There is no "right way", but there are a few simple principles to follow:

  • Create the composition root on application's startup
  • After the composition root has been created, throw the reference to the DI container / kernel away (or at least encapsulate it so it is not directly accessible from your application)
  • Do not create instances via "new"
  • Pass all required dependencies as abstraction to the constructor

Thats all. For sure, that are principles not laws, but if you follow them you can be sure that you do DI (please correct me if I am wrong).


So, how to create objects during runtime without "new" and without knowing the DI container?

In case of NInject, there is a factory extension that provides the creation of factories. Sure, the created factories still have an internal refernce to the kernel, but that is not accessible from your application.

protected by Community Jun 27 '16 at 18:34

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.