Continuing the topic from the previous posts.
What would happen?
Current behavior of Windsor is somewhat flawed. What it will do is it will resolve foo, and provide it with bar. The flaw of this behavior is that now when we resolve foo via any of the tree containers we’ll get the same instance (since it’s a singleton). This introduced two issues:
- component from childA (bar) will now be available via childB and parent while logically thinking – it should not.
- we have temporal coupling in our code. Depending on the order of containers we’ll use to resolve foo we’ll get different results
So what should happen?
Ok, so now that we agreed that current behavior is indeed flawed (we did, didn’t we?) what are our options for fixing it? We basically have two options (both of which were mentioned in comments to previous post).
It all boils down to scoping. If we have a per-web-request object – should single instance be shared among multiple containers or should it be per-web-request-and-per-container? If we have singleton should it be single instance per container, per container hierarchy or per process?
Let’s consider slightly more complicated picture.
Now we have two components for bar, one in childA and one in parent. Also we have one more component; baz, which is registered in childB.
Baz has dependency on foo, foo still has dependency on bar. All of these dependencies are optional, and all components are singletons.
There can only be one
We want to scope instances strictly per their container. So that foo is scoped in parent (thus visible from its child containers as well), and bar is scoped per childA. This appears to be the simplest setup, and the most in line with definition of singleton, but then we run into problems outlined above.
We then could add another constraint – dependencies can only face upwards the container hierarchy. We would then get foo with its dependency on bar pulled from parent container, consistently, regardless of the container we’d resolve it from. Moreover, we could resolve baz from childB and its dependency would be properly populated from parent since it comes from a container that is higher in the hierarchy, so we’re safe to pull that dependency.
On the other hand this robs us of one of nice (and often used) side effect of child containers, that is contextual overriding of components from containers higher up the hierarchy.
If we have bar in childA, we’d expect to get foo pulled via childA to have that bar, not parent’s bar.
Or perhaps not?
We can approach the problem from another angle altogether. We can narrow down the scope of a component instance, to the scope of its outermost dependency. What do I mean by that?
When resolving foo from childA the outermost dependency of foo would be the bar living in childA. Therefore the instance of foo would have bar pulled from parent, but scoped in childA. Therefore when we’d request foo again, but this time from childB we’d get another instance of foo, with dependency on bar pulled from parent. This could potentially lead to problems as well, since if you’re depending on the fact that single instance of your component will ever live in the application at given point in time you may end up with problems.
So what do you think? Which approach would you prefer, or is there something I’m missing here?
To those who though I’m seriously going to remove support for nested containers rest assured this is not going to happen. I still think this could be a viable option and I wanted to throw it into the air, but its become such a core feature of each IoC container, that Windsor would look crippled if it didn’t have it, regardless of whether or not it’d be actually needed.
06-04-2010 5:05 AM