Inject into child container

Dec 10, 2008 at 1:00 AM
Edited Dec 10, 2008 at 1:03 AM

Hi, I am fairly new to Di and the Unity Application block, I am having a hard time trying to Inject a UnityContainer into a child container using the parent.CreateChildContainer method.

Any ideas?

 

    public class RootContainer
    {
        private IUnityContainer _container;

        public RootContainer()
        {
            _container = new TestUnityContainer();
            _container.RegisterType<IChildContainer, ChildContainer>();
           
            // Method 1 - Associate a new instance with the IUnityContainer
            //_container.RegisterInstance<IUnityContainer>(_container.CreateChildContainer());

            IChildContainer child = _container.Resolve<IChildContainer>();
        }
    }

    public interface IChildContainer { }

    public class ChildContainer : IChildContainer
    {
        private IUnityContainer _container;

        /* I want to inject the parent.CreateChildContainer() into this constructor */
        public ChildContainer(IUnityContainer container)
        {
            _container = container;
        }
    }

 

 

 

 

 

 

 

 

 

 

 

Dec 10, 2008 at 6:47 AM
Hi,

You can try this, In your _container.RegisterType<IChildContainer, ChildContainer>();, you can add a injectionConstructor in the parameter to specify the value that will be passed to the constructor of the type you are registering. like this,

_container.RegisterType<IChildContainer, ChildContainer>(new InjectionConstructor(_container.CreateChildContainer()));


Valiant Dudan
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

 

Dec 10, 2008 at 8:20 AM
Edited Dec 10, 2008 at 8:21 AM
Is it possible to do this when the object is creaed.  For example, can I create an UnityContainerExtension that will register a custom IBuildPlanPolicy that will inject child containers.   I was having some success with this method however I was unable to locate the constructing container from the IBuilderContext

    class Program
    {
        static void Main(string[] args)
        {
            IUnityContainer container = new UnityContainer();
            container.AddNewExtension<MyUnityContainerExtension>();

            container.RegisterType<IUnityContainer, MyUnityContainerDecorator>();
        }
    }

    public class MyUnityContainerDecorator : IUnityContainer
    {
        private readonly IUnityContainer _container;

        public MyUnityContainerDecorator(IUnityContainer container)
        {
            _container = container;
        }

 /* IUnityContainer members not implemented in this example */
    }

    public class MyUnityContainerExtension : UnityContainerExtension
    {
        protected override void Initialize()
        {
            this.Context.Policies.Set<IBuildPlanPolicy>(new MyBuildPlanPolicy(), NamedTypeBuildKey.Make<MyUnityContainerDecorator>());
        }
    }

    public class MyBuildPlanPolicy : IBuildPlanPolicy
    {
        public void BuildUp(IBuilderContext context)
        {
            /* How can i get a reference to the constructing IUnityContainer */
            if (context.Existing == null)
            {
                context = new MyUnityContainerExtension(/* container.CreateChildContainer() */);
            }
        }
    }

Dec 14, 2008 at 11:40 AM
Edited Dec 14, 2008 at 11:41 AM
I'm not sure what you're trying to do here but there may be another simpler way to do this.  Anyway, I don't think you could get an instance of an IUnityContainer in the IBuilderContext.  It contains current policy set and strategies that are being executed.  You may want to check these posts by Chris Tavares...
http://www.tavaresstudios.com/Blog/post/Deconstructing-ObjectBuilder---What-Is-ObjectBuilder.aspx
http://www.tavaresstudios.com/Blog/?tag=/objectbuilder

Regarding your first code sample, it may have something to do with your implementation inside the TestUnityContainer.


Sarah Urmeneta
Global Technology & Solutions
Avanade, Inc.
entlib.support@avanade.com






Dec 14, 2008 at 6:32 PM
Could we back up a little here? Rather than telling us about the solution you're trying to build, could you tell us what problem you're trying to solve? There may be other ways to approach it.

By the way, registering IUnityContainer inside the container is a bad idea. The current container is automatically registered with itself as part of supporting the new collection injection feature. Overwriting that registration could cause lots of things to break.

Dec 14, 2008 at 7:27 PM
Chris,

Could you give some clarification this statement,
By the way, registering IUnityContainer inside the container is a bad idea. The current container is automatically registered with itself as part of supporting the new collection injection feature. Overwriting that registration could cause lots of things to break.
Are you specifically talking about re-registering the type as in examples above,
container.RegisterType<IUnityContainer, MyUnityContainerDecorator>();
As opposed to registering the container instance with itself,
container.RegisterInstance<IUnityContainer>(container);
Phil
Dec 14, 2008 at 9:48 PM
Both, actually.

By default, the container is registered with itself. As such, if you reregister a different container, you will most likely break array resolution.

In the second case, you'd think that would just be a no op, but there's a nasty little bug there. Calling RegisterInstance by default uses the ContainerControlledLifetimeManager. As such, when the container is disposed, it'll also dispose anything managed by a ContainerControlledLifetimeManager. So when you Dispose the container, it'll find itself, try to dispose itself, and round we go until you run out of stack space.

We've correctly handled this case under the hood, so you don't need to worry about it, but if you do it yourself all bets are off.

-Chris

Dec 15, 2008 at 5:17 AM
In the second case, you'd think that would just be a no op, but there's a nasty little bug there. Calling RegisterInstance by default uses the ContainerControlledLifetimeManager. As such, when the container is disposed, it'll also dispose anything managed by a ContainerControlledLifetimeManager. So when you Dispose the container, it'll find itself, try to dispose itself, and round we go until you run out of stack space.

The reason I asked the second part of the question is due to the Composite WPF and Silverlight project. In their source Microsoft.Practices.Composite.UnityExtensions.UnityBootstrapper, they perform that exact registration of the contain in the container.  I was trying to determine if that was something they should be aware of or it was ok.
        protected virtual void ConfigureContainer()
        {
            Container.RegisterInstance<ILoggerFacade>(LoggerFacade);
            Container.RegisterInstance<IUnityContainer>(Container);
            Container.AddNewExtension<UnityBootstrapperExtension>();

Dec 15, 2008 at 6:45 AM
Actually, Bob (the Prism dev lead) and I talked about this last Wednesday. They've taken this registration out of their code for exactly the reasons I mention above. I assume the change will be in the next drop.
Dec 15, 2008 at 6:49 PM
Edited Dec 15, 2008 at 6:56 PM
Thanks for the info,

Hi Chris, here is the original problem i was trying to solve.

The original problem relates to the root of this discussion.  I want to create an object "RootContainer" that contains an IUnityContainer, when i build up the "ChildContainer" i want to automatically inject a child container, using the CreateChildContainer method,  each time i see a reference to an IUnityContainer, for example in the Constructor of the ChildContainer.

Here is how i currently implemented the solution, any advice would be greatly appreciated.

First of all i started with a new Strategy to intercept the build process

public class UnityInversionStrategy : BuilderStrategy
{
    public override void PreBuildUp(IBuilderContext context)
    {
        // Intercept all calls for creating IUnityContainers
        
if (context.BuildKey.Equals(NamedTypeBuildKey.Make<IUnityContainer>()))
        {
            ILifetimeSupportPolicy unityContainerLocator = context.Policies.Get<ILifetimeSupportPolicy>(context.BuildKey);
            if (unityContainerLocator != null)
            {
                IUnityContainer unityContainer = unityContainerLocator.Locate<IUnityContainer>(context);
                if (unityContainer != null)
                {
                    context.Existing = unityContainer.CreateChildContainer();
                    context.BuildComplete = true;
                }
            }
        }
    }
}

After that i created a new Policy to perform the build up of the previously registered IUnityContainer

public interface ILifetimeSupportPolicy : IBuilderPolicy
{
    T Locate<T>(IBuilderContext context);
}
public class LifetimeSupportPolicy : ILifetimeSupportPolicy
{
    public T Locate<T>(IBuilderContext context)
    {
        // Fetch the currently registered IUnityContainer from the ILifetimePolicy using the LifetimeStrategy
StagedStrategyChain<BuilderStage> strategyStages = new StagedStrategyChain<BuilderStage>();
        strategyStages.AddNew<LifetimeStrategy>(BuilderStage.PreCreation);
        return (T) strategyStages.MakeStrategyChain().ExecuteBuildUp(context);
    }
}

And finally created the UnityContainer Extension

public class UnityContainerInversionExtension : UnityContainerExtension
{
    protected override void Initialize()
    {
        this.Context.Policies.Set<ILifetimeSupportPolicy>(new LifetimeSupportPolicy(), NamedTypeBuildKey.Make<IUnityContainer>());
        this.Context.Strategies.AddNew<UnityInversionStrategy>(UnityBuildStage.TypeMapping);
    }
}
Jan 21, 2009 at 8:17 PM
In the second case, you'd think that would just be a no op, but there's a nasty little bug there. Calling RegisterInstance by default uses the ContainerControlledLifetimeManager. As such, when the container is disposed, it'll also dispose anything managed by a ContainerControlledLifetimeManager. So when you Dispose the container, it'll find itself, try to dispose itself, and round we go until you run out of stack space.

We've correctly handled this case under the hood, so you don't need to worry about it, but if you do it yourself all bets are off.

Before reading this discussion, I had tried the above and yes, stuck myself with a stack overflow exception.  I am using a child container and resolving IUnityContainer
on the child container gives me the parent container.  Here's test code I wrote to prove it to myself

IUnityContainer child = container.CreateChildContainer();
IUnityContainer resolved = child.Resolve<IUnityContainer>();
System.Console.WriteLine("child:" + (resolved == child));
System.Console.WriteLine("container:" + (resolved == container));

The results are
child:False
container:True

Is this a bug or am I doing something wrong?  Thanks.