Castle Windsor and child containers: Revolutions

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.

containers_2

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.

classes_2

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.

  • can you do both?

    first option == Lifestyle.Singleton
    second option == Lifestyle.Container

  • @blingcode

    Like I said in previous post, this is true for any non-transient lifestyle not just singleton, so I’d have to have scoped version of each and every lifestyle except for transient

  • Omer Mor

    continuing with that thought: You can start a new orthogonal dimension, in addition to Lifestyle, for example – Scope.
    Then you could have:
    LifeStyle.Singleton + Scope.Container
    or
    LifeStyle.Singleton + Scope.Hierarchy

    This might also open up the possibility for Scope.AppDomain (via shared static container, yuck).

  • hammett

    Is that true? The dependency resolution should always go up the container hierarchy.

  • Vinay

    If I had to choose between the 2 options you’ve presented, I would choose the first. It seems (IMO) that support for a true singleton instance of a component within an application would be a more vital and more useful feature than contextual overriding components in child containers, but that is strictly my opinion which might be wrong.

    I too, however, like the idea of supporting both and find that Omer’s suggestion of introducing the concept of ‘scope’ adjacent to lifestyle could be a very elegant solution.

  • Vinay

    follow up question:

    How would the introduction of a ‘scope’ affect a child containers ability to resolve components registered within a parent container?

    For example, if the parent container in the above example had been configured with ‘container’ scope, would either of its children be able to resolve foo? Do you really need to offer another behavior for this?

    Upon further reflection, maybe ‘scope’ isn’t the concept we should be trying to define here. Maybe all we need is a way to specify that a component registered within a child should be used to override the dependecies of components coming from its parent. Via the fluent api, it could read something like ‘UseAsParentDependencyOverride’.

    IMO, I still believe that allowing a parent container to resolve components registered by its children is a dangerous road. Maybe the ‘UseAsParentDependencyOverride’ option would only be considered when the parent component is resolved using that specific child container, and that parent component has a transient lifestyle. This way, you would still avoid the 2 problematic issues mentioned above.

  • @Vinay
    I don’t think you would configure containers with scope. I think what Omer meant you would configure components with it, so that component can decide if it accepts dependencies from child containers or not.

    What I’m going to investigate at the moment is yet another solution:
    Go with "There can be only one" approach and allow IHandlerSelectors or ISubDependencyResolvers to provide overrides from child containers.

    No plan as to how that would actually work. At this stage it’s just an idea. This has the advantage of not introducing yet another concept.

  • AndyZ

    What if you were to add a lifestyle of "ResolveFromParent"? When adding a child container it copied its parent configuration leaving all the transient items as transient and changing all other items to "ResolveFromParent". This could be the default behavior but other behaviors could be implemented.

    Once a child was constructed it would the behave like your option 1. If the user of the container added new definitions then they would override/extend the inherited definitions. This would allow changing individual definitions to behave like option 2 if desired.

    It may also be possible to implement a "ResolveFromOtherContainer" where the specific "parent" container could be specified on a per component basis, but this would probably be too complicated.

  • AndyZ

    Sorry, I forgot to mention that if "ResolveFromParent" is used then and dependencies on the component in the parent container will only resolve from the parent container. In fact all dependencies will only be resolved from the current container unless an explicit "ResolveFromParent" lifestyle is encountered.

  • Kurt Harriger

    My thought is that instances should scoped to the container from which from which they are resolved rather than the container in which they are registered. So even though foo is registered in parent container when resolved through child b the instance should be stored in child b, so you could have a dependency on baz but that instance of foo only visible when resolved from the child b container. When resolved from child a, a new instance of foo would be created for child a container that could depend on bar but not baz. Although this seems to violate "singleton" pattern it is well understood that lifetime is managed by the container so if you create multiple containers you could have multiple instances of foo.

    So then what do you do if you what to use the same instance of foo in both child a and child b? Register a factory method that resolves the instance of foo from a shared container. Parent/child relation is not needed here. The shared instance however would not be able to depend on any components from child a or child b as the shared container does not know about these components, nor should it for all the reasons you mentioned. When child b container is disposed, foo’s reference to baz would be invalid.

    If one really needs a single shared instance of foo which also directly depends on baz, they are doing it wrong. If one really needed foo to be shared and be able to obtain an instance to baz, then one could inject a BazProvider into foo that how to find the current instance of baz when it is needed, if there is one. This might be provided in thread static variable and scoped with something like using(new BazScope(baz)) { foo.DoSometingWithBaz(); }. In this case, you would probably be easier to just pass baz in as a method parameter, but if baz is something like an HttpRequest than it might be useful to inject Foo with an IHttpRequestProvider that would return request from the HttpContext.Current so that caller does not need to provide the context as a method parameter.

    So, it may be useful to have multiple containers at for different scopes but they really don’t need a parent/child relationship. If there is a child/parent relationship the instance should only be visible to the container from which it was resolved to avoid leaking dependencies into other child containers.

  • AndyZ

    One more consideration…

    What about the situation where you have only a single container but a singleton object depends upon an object with a thread lifestyle? This is similar to the child container issue in that a singleton object will now depend on an object which has a different (narrower) context.

    I think that the solution to this is the concept of "context". Each object is built in an N-dimension space. Each object has a (possibly partial) set of coordinates associated with it which define the region of space for which the object is valid (its context).

    Each of the object’s dependencies’ regions must intersect the parent object’s region.

    Some dimensions are implicit to the request (request id, container id , thread id) and some must be specified explicitly (web request id, active user, whatever).

    When the container gets a request to resolve an object, the request will have a set of coordinates associated with it which define the region to resolve in.

    For transient objects the object is created with the exact coordinates which were specified. For singleton objects the object is created where the container dimension is fixed to the container in which the singleton was defined and all other dimensions are undefined.

    When an object is being created all injected objects are requested to be part of the parent object’s region of space.

    Some portions of space can be destroyed (i.e. a thread terminates, a container is disposed, a requested object is released, etc.). When this happens then all objects contained in that region of space are disposed.

    I know that this is kind of a crazy idea. When I have time I’ll try and write up some examples or perhaps even try to code the logic.