views:

168

answers:

4

When using a dependency injection container, missing dependencies are detected when you execute resolve. This is at runtime.

This article describes a partial solution. It would help simplify test, debug, and maintenance, but it still requires tests to be executed to validate your behavior (especially if you use the abstract factory sub-solution for runtime resolution):

http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx

When using dependency injection containers, is there a way to determine at statically that all of your dependencies will be resolved?

+2  A: 

Short answer: no, it can't be done.

Doing this would require being able to represent all components and their dependencies (the container metadata) as a graph, in order to analyze it. Problem is, the more sophisticated the container, the harder it gets to achieve this. Take for example Windsor. Its numerous extension points make the dependencies too dynamic to be represented as a graph. Lazy component loaders, handler selectors, factories, componentmodel contributors, subresolvers, all participate in the process and they can be arbitrary user code, which makes it impossible to analyze statically.

A static analysis might be feasible for a trivial container, but then this hypothetical container would be pretty useless for real-world projects.

So as usual it's a trade-off, and the best we can do is have some tests that exercise the actual resolution of all registered components in the container. StructureMap has a AssertConfigurationIsValid() method to do just that.

Even so, there could be more subtle errors that are not caught by this, such as lifestyle issues.

Mauricio Scheffer
Best practices are definitely interesting and useful to me. I happen to be looking into Windsor, so that's particularly relevant to me. Thanks for the useful links :)
Merlyn Morgan-Graham
+4  A: 

The Managed Extensibility Framework (MEF) can do this. There are some best practices that you need to adhere to in order for the analysis to be accurate, but the results are otherwise good.

To analyse a set of assemblies a command-line tool is used - see http://blogs.msdn.com/b/nblumhardt/archive/2009/08/28/analyze-mef-assemblies-from-the-command-line.aspx. This can be run from Visual Studio or a build script in a continuous integration server - http://blogs.msdn.com/b/nblumhardt/archive/2009/09/24/debug-composition-from-within-visual-studio.aspx.

You can do it visually (again over a set of assemblies) using the MefContrib project's Visual MEFX - see http://xamlcoder.com/blog/2010/04/10/updated-visual-mefx/

MEF supports this functionality by being both very declarative (standard attributes for configuration) and by using an underlying composition model that works lazily (it can build the graph without creating any instances... Takes a bit to wrap your head around.)

Cheers, Nick

Nicholas Blumhardt
Cool! never thought it would be possible. However, to be fair, it *should be* possible in Windsor since it also represents components as graph nodes, but only for a very restricted/static usage of the container...
Mauricio Scheffer
Yes- it is more about the scope of what can be analysed rather than an all-or-nothing question. MEF goes a bit further making things like the equivalent of the Typed Factory Facility able to be analysed. Will be interesting to see what Krzysztof has cooking for Windsor v.3 :)
Nicholas Blumhardt
+1  A: 

In addition to what Mauricio said, Windsor 2.5 has a feature that you might find useful when diagnosing issues with missing dependencies or just looking through the components in the container.

I blogged about beta version of it here. It's now quite more useful and as everything in Windsor - it's extensible so you can out your own items on that list.

alt text

Krzysztof Koźmic
A: 

Maybe not with a dependency injection container. However, you can do dependency injection manually, without a container. For example:

var foo = new Foo();
var bar = new Bar(foo);
var program = new Program(bar);
program.Run();

If it compiles then all the dependencies are there.

However, trouble looms as soon as the dependency graph grows large enough that you can't keep it entirely in your head (espcially with some circular dependencies thrown in the mix). If you do refactorings that involve rearranging of dependencies, then it will become hard work to adapt the order of constructor calls.

Wim Coenen
While I appreciate your answer, it isn't terribly useful to me :) I want my team's code to separate construction of dependencies and access to dependencies. This use of DI makes it easy to forget, or to slip up unintentionally. That's why I'm going to advocate use of a DI container and/or abstract factories.
Merlyn Morgan-Graham
@Merlyn: I don't really understand what you mean. Manual dependency injection keeps the construction phase separate from the rest of the code in exactly the same way as with a container. The above code snippet is equivalent to what `var program = container.Resolve<Program>();` would do, and would appear at the same place in the code.
Wim Coenen
@Wim: Sorry I should correct myself. When I said access, I meant filling a dependency slot. I am using this as a solution for test isolation, so I can inject mocks. Unless I abstract the exact dependency passed to code, then I'm locked with whatever implementation the calling code passed. The two solutions I know of are abstract factory classes (which would allow me to do the static checking you're describing here) and DI containers (which is what my question is about). I am already planning to use constructor injection in either/both cases.
Merlyn Morgan-Graham