Child container questions

Feb 6, 2009 at 11:04 AM
I have an "object space" (which is like a unit of work + local caching).  So far I have been creating interfaces like this

public interface IPersonRepository
{
  Person GetByID(IMyObjectSpace objectSpace, int id);
}

It is essential that the object space it passed in whenever domain objects are worked with otherwise I lose my "context".  What has dawned on me though is that I could create a child container that has the instance of IMyObjectSpace registered in it instead.  But this leads me to the following question:

If IPersonRepository is registered in the main container, when I request it in my child container it will retrieve it from the parent container wont it?  So when PersonRepositoryImpl is created, expecting IMyObjectSpace it will try to resolve it in the parent container and not the child container that initiated the request.  Is there any way I can control this?


Pete
Feb 6, 2009 at 6:07 PM
The answer depends on what you mean by "registered int the main container." The real issue is the lifetime manager being used and which container it's configured in; the injection configuration doesn't affect this.

If IPersonRepository is registered with the ContainerControlledLifetimeManager in the parent container, and then you resolve it through the child container, then it'll end up storing that child's instance in the parent container, and result in the issue you're worrying about.

If IPersonRepository is registered with the ContainerControlledLifetimeManager in the child container, and then you resolve through the child container, that instance will be stored in the child container, not in the parent. Future resolves through the child container will get the proper instance.

If IPersonRepository is transient (the default) then a new one will be built every time and you'll be fine.

So, the thing to remember is if you're using child containers, don't set lifetimes in the parent container, only set it in the children (unless it's something you definately want shared across all the child containers).

Hope this helps,

-Chris

Feb 6, 2009 at 9:40 PM
Hi Chris

Let's say I register IPersonRepository in the main container using a transient lifetime, to ensure that the "object space" is injected each time I request it.  Now I create a child container and in that container I register an instance (my object space).  If I ask my child container for IPersonRepository which of the following will happen?

A: Child container doesn't have IPersonRepository so asks its parent container.  Parent container sees it is transient and creates an instance.  Sees it needs ObjectSpace as a constructor parameter but cannot find it because there isn't one in the parent container.
B: As above, but when it needs to resolve other dependencies it starts at the child container again and finds the ObjecSpace

I'm just trying to understand how it works.

Thanks
Feb 6, 2009 at 9:49 PM
I think this simple code demonstrates my answer:

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.Unity;

namespace ConsoleApplication24
{
    class Program
    {
        static void Main(string[] args)
        {
            UnityContainer container = new UnityContainer();
            container.RegisterType<IPersonRepository, PersonRepository>(new TransientLifetimeManager());
            var childContainer = container.CreateChildContainer();
            childContainer.RegisterInstance<ObjectSpace>(new ObjectSpace { Name = "Hello" });
            var repository = childContainer.Resolve<IPersonRepository>();
            Console.WriteLine(repository.ObjectSpaceName);
            Console.ReadLine();

        }
    }

    public interface IPersonRepository
    {
        string ObjectSpaceName { get; }
    }

    public class PersonRepository : IPersonRepository
    {
        readonly ObjectSpace ObjectSpace;

        public PersonRepository(ObjectSpace objectSpace)
        {
            ObjectSpace = objectSpace;
        }

        public string ObjectSpaceName
        {
            get { return ObjectSpace.Name; }
        }

    }

    public class ObjectSpace
    {
        public string Name { get; set; }
    }
}


It shows that the PersonRepository *IS* fixed up with references from the child repository, so that's a good thing.  So what I need to know now is what is a good way to manage child container life times?  Are they automatically collected when I no longer hold a reference to them, or does the parent container hold a reference to them and keep them alive?


Thanks :-)

Feb 6, 2009 at 10:29 PM
Ahh, I see the conceptual gap. We'll need to see if we can improve the docs around this.

A child container doesn't "ask it's parent" to resolve something. Instead, there's kind of a merge of the strategies and policies under the hood. Child policies can override what's in the parent, but there's no explicit call up the parent chain. It makes perfect sense if you know the internals, but you really shouldn't have to know the internals to use the container. Anyway, I can see from your code above you've already gotten the right answer.

As far as lifetime goes, parent containers do NOT hold a reference to children. You are free to manage their lifetime however you want; by default it's handled just like any other .NET object. Children do hold a reference to their parent container (obviously).

I would strongly recommend you call Dispose on the child container when you're done with it, as that will also dispose any ContainerControlledLifetime objects in that container as well.

Feb 7, 2009 at 8:07 AM
Hi Chris

Thanks for the info!  Your description + what I observe though confuses me slightly.  If creating a child container merges the definitions down...

            UnityContainer container = new UnityContainer();
            container.RegisterType<IPersonRepository, PersonRepository>(new ContainerControlledLifetimeManager());

            DoChildContainer(container, "Hello 1");
            DoChildContainer(container, "Hello 2");
            Console.ReadLine();
        }

        private static void DoChildContainer(UnityContainer container, string name)
        {
            var childContainer = container.CreateChildContainer();
            childContainer.RegisterInstance<ObjectSpace>(new ObjectSpace { Name = name });
            var repository = childContainer.Resolve<IPersonRepository>();
            Console.WriteLine(repository.ObjectSpaceName);
        }
    }

From your description the first time I call DoChildContainer I would expect the registration of IPersonRepository to be passed down to the child, then I would expect resolving it would pass in the object space that I registered in the child container (which it does).  But if the child container isn't touching the parent container why is it that the 2nd call to DoChildContainer doesn't create a new instance of IPersonRepository, instead it returns the first one that was created?  I would have expected the definition to be passed down, but for the instance to only exist in the child container and not get shared with the 2nd child container instance.

That's the kind of behaviour I am trying to achieve anyway, so that I can create container controlled lifetimes for services in child containers without them interfering with each other and without having to register their types in the child container directly.


Pete
Feb 9, 2009 at 8:04 PM
I think it's time to actually dive into the internals. This should clear things up (I hope).

All of the internal configuration of a container is stored in a data structure called a PolicyList. The PolicyList stores policy object. A policy object is something like an IBuildKeyMappingPolicy, which maps one type/name pair to another, or an IConstructorSelectorPolicy, which determines which constructor to call, or, most importantly for this discussion, the ILifetimePolicy, which is implemented by the lifetime manager classes.

PolicyList has a parent chain. When you request a particular policy for a particular type/name pair, if it's not found in the current PolicyList, it'll ask the parent PolicyList. If the parent doesn't have it, it'll ask the grandparent, etc. Each container has it's own PolicyList, and child containers have a PolicyList that points to the parent's PolicyList as a parent.

Now here's the thing - when adding a policy, it gets written into the local PolicyList only.

So, let's walk through two scenarios. The first:

    IUnityContainer container = new UnityContainer() ... ;
    var childContainer = container.CreateChildContainer();
    childContainer.RegisterType<Foo>(new ContainerControlledLifetimeManager());
    childContainer.Resolve<Foo>();

Here, by calling RegisterType<Foo>, we've added a ILifetimePolicy to the child's PolicyList, but not the parents. When you resolve from the child container, it looks for ILifetimePolicy, finds it in the local PolicyList, and proceeds to operate as expected. If you had instead done container.Resolve<Foo>(), it would look in the parent PolicyList only (we never look into child PolicyLists), not find one, and use the default transient object behavior.

So, let's change the scenario:

    IUnityContainer container = new UnityContainer() ... ;
    var childContainer = container.CreateChildContainer();
    container.RegisterType<Foo>(new ContainerControlledLifetimeManager()); // <-- parent container now, not child
    childContainer.Resolve<Foo>();

So what happen here? When resolving in the child container, it goes looking for ILifetimePolicy. It doesn't find it in the child PolicyList, so it goes looking in the parent's, and does find it there.

Now, what happens next is that the object gets built, and then it gets stored in the LifetimeManager for later retrieval. But remember, that LifetimeManager is in the parent! We're not creating a new lifetime manager in the child, we're simply using the one that was already found - in the parent.

So it's not that configuration is "passed down" from parent to child, it's that the child goes looking locally first, and on not finding something looks again in the parent.

Does that help?

-Chris

Feb 9, 2009 at 9:13 PM
So the child does go to the parent to resolve the instance for it then?  This means that I would have to register the IPersonRepository using a transient lifetime manager then?

I wonder, is there a way I could get the child container to look in the parent for the policy but have the child create the instance?  In the example of PersonRepository I would want to register it in the parent container for convenience, but only create instances in child containers where there is an ObjectSpace registered.  Can this be done?  Otherwise I'd have to make PersonRepository transient, and if there are a lot of dependencies required (all requiring ObjectSpace) then there is going to be a lot of object creation going on each time I need to resolve a service.

Finally, is there a commonly used pattern for creating/disposing child containers?  I would expect to do something like

using (var childContainer = UnityContainer.CreateChildContainer)
{
  childContainer.RegisterInstance<IUnityContainer>(childContainer);
  AppLayerDoSomeStuff(childContainer);
}

Thanks for your help, I appreciate it!
Feb 9, 2009 at 10:45 PM

The logic for resolving executes in the child container. That logic looks up a variety of policies along the way. Some of those policies will come from the child, other will look up to the parent, depending on how the child container is configured.

In your case of PersonRepository, by "register it in the parent container for convenience", do you mean set up the injection properties? That is, what constructor to call, which properties to set, etc? If so, yes, you can do that and then resolve through the child containers. The one thing you can't do is set the lifetime manager in the parent - you must configure that in each child or you get the issue of the child's resolved value ending up in the parent as discussed above. You can call RegisterType multiple times, BTW. The lifetime manager and injection configuration set different policies, so they can be set through separate calls.

So what I'd do is configure injection in the parent, lifetime in the child, and it'll all just work the way you want.

As for your proposed pattern, never register a container with itself. It's already done for you (new in Unity 1.2) so you don't gain anything, and you'll get a stack overflow at dispose time. Just add a dependency on IUnityContainer in your objects and it'll just work.

Feb 10, 2009 at 8:57 AM
Hi Chris

Thanks for the tip regarding self registration.  As for registering the services.  The way our app is set up is to dynamically load all assemblies in a specified folder, look for classes that implement IModule, and then create an instance of that module and get it to register its services.

{
  unityContainer.RegisterType<IPersonRepository, PersonRepository>(new ContainerControllerLifetimeManager());
  etc
}

We do not have any injection properties etc, just mapping interfaces to implementers.  But because this app is written in a modular way it means that the child container wont know all of the services implemented by the parent container, and the ones it is aware of it wont know which classes implement the interface.

Now, I could create some code which creates the child container and sets the lifetime manager for certain services etc, but the problem with this is that it creates 2 places to update whenever a new service is created.  First the new service has to be registered in its relevant module, and then the code that creates the child container + registers the lifetime managers needs to be updated for this new service too.  Having a requirement to have a service registered in two places is going to lead to problems, some people are going to forget to do it (myself included I suspect).

I tried registering the type with the parent container without specifying the lifetime, but this results in a transient registration which I would like to avoid.

What I think I need is
01: Register the type/implementer in the parent container - must be this way due to the module discovery which happens via reflection in Application_Start in Global.asax
02: For certain services that I identify some how in the registration the instance should be registered in the container resolving it and not the container registering it.  So that when a service requires an ObjectSpace for example, which is only registered in the child container, that service implementer's instance will exist in the child container so as not to conflict with any other child containers that require the same service but using a different ObjectSpace.

I am starting to suspect this is currently not possible?  If it is then I'd love to know how, if it isn't then maybe I could work out my own lifetime manager implementation but for this I'd need a reference to the container that called Resolve when GetValue is called.  Would either scenario be possible?

Thanks

Pete
Feb 10, 2009 at 1:36 PM
I posted my post at 9:57.  My current view of this forum shows no response.  The RSS feed shows you replied at 11:31 (that was quick!), but unfortunately the RSS feed shows an incomplete message.

========
I think this simple code demonstrates my answer:

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.Unity;

namespace ConsoleApplication24
{
    class Program
    {
        static void Main(string[] args)
        {
            UnityContainer container = new UnityContainer();
            container.RegisterType<IPersonRepository, PersonRepository>(new TransientLifetimeManager());
            var childContainer = container.CreateChildContainer();
            childContainer.RegisterInstance<ObjectSpace>(new ObjectSpace { Name = "Hello" });
            var repository = childContainer.Resolve<IPersonRepository>();
            Console.WriteLine(repository.ObjectSpaceName);
            Console.ReadLine();

        }
    }

    public interface IPersonRepository
    {
        string ObjectSpaceName { get; }
    }

    public class PersonRepository : IPersonRepository
    {
        readonly ObjectSpace ObjectSpace;

        public PersonRepository(ObjectSpace objectSpace)
    &
========

Which obviously doesn't demonstrate your answer :-)

Would you mind reposting please?

Feb 13, 2009 at 8:00 AM
Chris?

I'm dying to see your whole post :-)  Or isn't what I want possible?


Thanks

Pete
Feb 13, 2009 at 4:54 PM
My post is fine on the actual forum. Apparently it's just your copy of the feed that's screwed up. I'd rather not pollute the forum with reposts - can't you just read it directly from the web instead of in your RSS reader?

Feb 13, 2009 at 6:50 PM
Hi Chris

Ah, my mistake.  I thought it was your post that messed up.  I couldn't see it on the forum because I was only looking at posts in yellow.  It was in fact my own post that messed up.

My problem is that when creating the child container there is no way to know which services to create a new lifetime manager for.  The app uses Microsoft.Practices.Composite.Modularity.ModuleManager to dynamically discover modules and get them to register their service implementers.  Having the container know explicitly about these services would break the modularity, so I can't re-register services explicitly when a child container is created.

The behaviour I really need is for the child container to check if there is an instance in the parent container, if there is then use that, otherwise create an manage an instance in the child container.  This is because the child container will contain my ObjectSpace instance that these services require, and I really don't want to make these services transient because when there is a lot of dependencies I don't want to suffer the CPU penalty for having to create them every time.

What about creating a child container and having it copy policies from the parent container?  Or what about if I created a special lifetime manager that the child container looked for an reregistered as controller lifetime managed?  I am clutching at straws :-)

What I think would be the most logical implementation would be if I could register an instance and identify it as a child-only item, so any service that is resolved which requires this instance would be created in the same container as the instance it depends upon despite the fact that the service type is initially registered in the parent container (which in this case is unavoidable).

Any help you can offer would be greatly appreciated.  I would really like to get rid of the ObjectSpace parameter which is present as the first parameter of 80% of my services' methods.


Thanks


Pete
Feb 13, 2009 at 10:04 PM
Ok, I see where you're going now. It's not an unreasonable scenario. A single custom lifetime manager wouldn't do it, unfortunately, since the lifetime manager strategy doesn't care about which container it gets it from. So you'd need a custom extension to stick the new lifetime strategy in at buildup time.

I can think of a couple ways to do this, but I need to stew on it a little more before proposing an approach.

-Chris

Feb 14, 2009 at 7:59 AM
Thanks Chris for spending your brain power on this, I really appreciate it very much!
Feb 19, 2009 at 8:37 AM
Hi Chris

I was wondering if you'd had any thoughts on this?  Is it looking difficult / impossible?


Pete
Feb 21, 2009 at 4:55 AM
It's looking doable, but my entire family (including myself) has come down with a cold so I'm not thinking very clearly right now.

Feb 21, 2009 at 10:05 AM
Hi Chris

Yuck!  I hope you guys all get better soon.  One of the problems with having kids is that they are always bringing stuff home from school you don't want :-)

I'm glad it's looking doable though.  I'm more in a state of keenness than urgency.


Thanks


Pete

Mar 20, 2009 at 10:06 AM
Hi Chris

I trust you are all recovered now?  Actually my family all have colds now :-)

I'm hoping you could share your idea on how to make this work?


Thanks

Pete
Mar 23, 2009 at 11:26 PM
Edited Mar 26, 2009 at 9:41 PM
Pete,

I finally stole an hour to implement this. The intent was to implement a lifetime manager that give a "container controlled per child container" lifetime. I ended up calling it "Hierarchical Lifetime" - stole the name from Daniel Cazzulino.

There are three parts. Unfortunately you can't implement this solely within the lifetime manager itself because the required information isn't available through the lifetime manager interfaces. So, we start with the HierarchicalLifetimeManager itself:
    public class HierarchicalLifetimeManager : ContainerControlledLifetimeManager
    {
    }
There's no actual special logic needed here, but we need a separate type to have something to look for. Next up, we need an ObjectBuilder builder strategy. Its job is to look for a hierarchical lifetime, and then determine if it's local or from a parent. If it's from the parent, add a new hierarchical lifetime manager to the current container.

    public class HierarchicalLifetimeStrategy : BuilderStrategy
    {
        public override void PreBuildUp(IBuilderContext context)
        {
            var activeLifetime = context.PersistentPolicies.Get<ILifetimePolicy>(context.BuildKey);
            if (activeLifetime is HierarchicalLifetimeManager)
            {
                // did this come from the local container or the parent?
                var localLifetime = context.PersistentPolicies.Get<ILifetimePolicy>(context.BuildKey, true);
                if (localLifetime == null)
                {
                    // came from parent, add a ContainerControlledLifetime here
                    context.PersistentPolicies.Set<ILifetimePolicy>(new HierarchicalLifetimeManager(),
                        context.BuildKey);
                }
            }
        }
    }
And finally, a container extension to install the strategy:

    public class HierarchicalLifetimeExtension : UnityContainerExtension
    {
        protected override void Initialize()
        {
            // Add to type mapping stage so that it runs before the lifetime stage
            Context.Strategies.AddNew<HierarchicalLifetimeStrategy>(UnityBuildStage.TypeMapping);
        }
    }
Using this is pretty straightforward. Add the extension to the parent container - child containers will inherit the strategy so you don't need to do anything to them. Then set the HierarchicalLifetimeManager at the appropriate spots, and that's it. Some sample test code:

    [TestClass]
    public class WhenUsingHierarchicalLifetimeWithChildContainers
    {
        private IUnityContainer child1;
        private IUnityContainer child2;
        private IUnityContainer parentContainer;

        [TestInitialize]
        public void Setup()
        {
            parentContainer = new UnityContainer()
                .AddNewExtension<HierarchicalLifetimeExtension>();
            child1 = parentContainer.CreateChildContainer();
            child2 = parentContainer.CreateChildContainer();

            parentContainer.RegisterType<Foo>(new HierarchicalLifetimeManager());
        }

        [TestMethod]
        public void ThenResolvingInParentActsLikeContainerControlledLifetime()
        {
            var foo1 = parentContainer.Resolve<Foo>();
            var foo2 = parentContainer.Resolve<Foo>();

            Assert.AreSame(foo1, foo2);
        }

        [TestMethod]
        public void ThenParentAndChildResolveDifferentInstances()
        {
            var parentFoo = parentContainer.Resolve<Foo>();
            var childFoo = child1.Resolve<Foo>();

            Assert.AreNotSame(parentFoo, childFoo);
        }

        [TestMethod]
        public void ThenChildResolvesTheSameInstance()
        {
            var foo1 = child1.Resolve<Foo>();
            var foo2 = child1.Resolve<Foo>();

            Assert.AreSame(foo1, foo2);
        }

        [TestMethod]
        public void ThenSiblingContainersResolveDifferentInstances()
        {
            var foo1 = child1.Resolve<Foo>();
            var foo2 = child2.Resolve<Foo>();

            Assert.AreNotSame(foo1, foo2);
        }
    }


Mar 24, 2009 at 9:25 AM
Hi Chris

Works brilliantly, thanks so much!

Pete


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Unity;

namespace ConsoleApplication44
{
    class Program
    {
        static void Main(string[] args)
        {
            IUnityContainer container = new UnityContainer();
            container.AddNewExtension<HierarchicalLifetimeExtension>();
            container.RegisterType<ICustomerRepository, CustomerRepository>(new HierarchicalLifetimeManager());

            using (IUnityContainer session1Container = container.CreateChildContainer())
            {
                session1Container.RegisterInstance<ISession>(new Session(), new ContainerControlledLifetimeManager());
                session1Container.Resolve<SomeBusinessProcess>().Execute(1);
                session1Container.Resolve<SomeBusinessProcess>().Execute(1);
            }

            Console.WriteLine("===");
            using (IUnityContainer session2Container = container.CreateChildContainer())
            {
                session2Container.RegisterInstance<ISession>(new Session(), new ContainerControlledLifetimeManager());
                session2Container.Resolve<SomeBusinessProcess>().Execute(2);
                session2Container.Resolve<SomeBusinessProcess>().Execute(2);
            }

            Console.WriteLine("===");
            using (IUnityContainer session3Container = container.CreateChildContainer())
            {
                try
                {
                    session3Container.Resolve<SomeBusinessProcess>().Execute(3);
                }
                catch (ResolutionFailedException)
                {
                    Console.WriteLine("Session3 container correctly detected no session is available");
                }
            }

            Console.ReadLine();

        }
    }

    public class SomeBusinessProcess
    {
        ICustomerRepository CustomerRepository;

        public SomeBusinessProcess(ICustomerRepository customerRepository)
        {
            CustomerRepository = customerRepository;
        }

        public void Execute(int customerID)
        {
            Console.WriteLine("Fetching customer {0}", customerID);
            var customer = CustomerRepository.GetByID(customerID);
            Console.WriteLine("Got customer {0}", customer.ID);
        }

    }

    public interface ISession
    {
        int ID { get; set; }
    }

    public class Session : ISession
    {
        static int NextID = 1;
        public int ID { get; set; }

        public Session()
        {
            ID = NextID++;
        }
    }

    public interface ICustomerRepository
    {
        Customer GetByID(int id);
    }

    public class CustomerRepository : ICustomerRepository
    {
        static int NextID = 1;
        ISession Session;
        readonly int ID;

        public CustomerRepository(ISession session)
        {
            Session = session;
            ID = NextID++;
        }

        public Customer GetByID(int id)
        {
            Console.WriteLine("Repository {0} is using session {1} to get customer {2}", ID, Session.ID, id);
            return new Customer { ID = id };
        }

    }

    public class Customer
    {
        public int ID { get; set; }
    }
}

OUTPUT
Fetching customer 1
Repository 1 is using session 1 to get customer 1
Got customer 1
Fetching customer 1
Repository 1 is using session 1 to get customer 1
Got customer 1
===
Fetching customer 2
Repository 2 is using session 2 to get customer 2
Got customer 2
Fetching customer 2
Repository 2 is using session 2 to get customer 2
Got customer 2
===
Session3 container correctly detected no session is available

Mar 24, 2009 at 9:45 AM
PS: I really think this should be a standard part of the toolset, it's very useful!
Mar 24, 2009 at 5:55 PM
It's certainly a candidate for including in V2.

I would like to request that you do a thorough test pass on this code before deploying it. It hasn't been through any QA on our end; I just threw it together in an hour. I'm pretty sure it works, but there may be lingering nastiness in there I missed.

On a completely different note, you don't need to specify ContainerControlledLifetimeManager when using container.RegisterInstance - that's the default.

Mar 24, 2009 at 6:04 PM
It seems to work just fine for what I need it to do.  There are a few other things I think I might need to work out before I continue, but things are looking good :-)

As for ContainerControlledLifetimeManager, I like to be explicit :-)
Aug 3, 2009 at 5:11 PM
var parent = new UnityContainer().AddNewExtension<HierarchicalLifetimeExtension>();
var child = parent.CreateChildContainer();
var parent.RegisterType<DisposableFoo>(new HierarchicalLifetimeManager());

var foo = child.Resolve<DisposableFoo>();
child.Dispose();
Debug.Assert(foo.IsDisposed);

I expected the assert on the last line to pass as foo is scoped to the child container but it doesn't.
Is this a bug in HierarchicalLifetimeManager or am I misunderstanding this thing?

Also will HierarchicalLifetimeManager be in V2? It would be useful to me.

 

Aug 10, 2009 at 7:31 AM

hwiechers, I stumbled upon the same problem and solved it like this:

    public interface IHierarchicalLifetime
    {
    }

    public class HierarchicalLifetimeManager : ContainerControlledLifetimeManager, IHierarchicalLifetime
    {
    }

    public class HierarchicalLifetimeStrategy : BuilderStrategy
    {
        public override void PreBuildUp(IBuilderContext context)
        {
            ILifetimePolicy activeLifetime = context.PersistentPolicies.Get<ILifetimePolicy>(context.BuildKey);
            if (activeLifetime is IHierarchicalLifetime)
            {
                // did this come from the local container or the parent?                
                ILifetimePolicy localLifetime = context.PersistentPolicies.Get<ILifetimePolicy>(context.BuildKey, true);
                if (localLifetime == null)
                {
                    localLifetime = (ILifetimePolicy)Activator.CreateInstance(activeLifetime.GetType());
                    context.PersistentPolicies.Set<ILifetimePolicy>(localLifetime, context.BuildKey);
                    context.Lifetime.Add(localLifetime);
                }
            }
        }
    }

    public class HierarchicalLifetimeExtension : UnityContainerExtension
    {
        protected override void Initialize()
        {
            // Add to type mapping stage so that it runs before the lifetime stage            
            Context.Strategies.AddNew<HierarchicalLifetimeStrategy>(UnityBuildStage.TypeMapping);
        }
    }
Aug 11, 2009 at 2:56 PM
jnykiel wrote:

hwiechers, I stumbled upon the same problem and solved it like this:

    public interface IHierarchicalLifetime
    {
    }

    public class HierarchicalLifetimeManager : ContainerControlledLifetimeManager, IHierarchicalLifetime
    {
    }

    public class HierarchicalLifetimeStrategy : BuilderStrategy
    {
        public override void PreBuildUp(IBuilderContext context)
        {
            ILifetimePolicy activeLifetime = context.PersistentPolicies.Get<ILifetimePolicy>(context.BuildKey);
            if (activeLifetime is IHierarchicalLifetime)
            {
                // did this come from the local container or the parent?                
                ILifetimePolicy localLifetime = context.PersistentPolicies.Get<ILifetimePolicy>(context.BuildKey, true);
                if (localLifetime == null)
                {
                    localLifetime = (ILifetimePolicy)Activator.CreateInstance(activeLifetime.GetType());
                    context.PersistentPolicies.Set<ILifetimePolicy>(localLifetime, context.BuildKey);
                    context.Lifetime.Add(localLifetime);
                }
            }
        }
    }

    public class HierarchicalLifetimeExtension : UnityContainerExtension
    {
        protected override void Initialize()
        {
            // Add to type mapping stage so that it runs before the lifetime stage            
            Context.Strategies.AddNew<HierarchicalLifetimeStrategy>(UnityBuildStage.TypeMapping);
        }
    }

 

Looking at your use of IHierarchicalLifetime made me think we could make a generic version that allows us to give hierarchical capability to any existing lifetime manager.

By changing HierarchicalLifetimeManager to the following, I think it can do just that:

public class HierarchicalLifetimeManager<t> : LifetimeManager, IHierarchicalLifetime
    where t : LifetimeManager, new()
{
    private LifetimeManager _innerManager;

    public HierarchicalLifetimeManager()
    {
        _innerManager = new t();
    }

    public override object GetValue()
    {
        return _innerManager.GetValue();
    }

    public override void RemoveValue()
    {
        _innerManager.RemoveValue();
    }

    public override void SetValue(object newValue)
    {
        _innerManager.SetValue(newValue);
    }
}
Aug 11, 2009 at 3:46 PM

jaxoson, the decorator approach is not that simple, because lifetime managers are treated differently depending on whether they implement IDisposable. You'd need two generic hierarchical lifetime classes - one that implements IDisposable (delegating it to the _innerManager) in addition to one that doesn't, which you posted. If you decorate a disposable lifetime manager with the class you posted, the objects it manages won't get disposed.

Aug 13, 2009 at 3:13 AM
Edited Aug 13, 2009 at 3:22 AM

Thanks for the info jnykiel. Other than any performance hit of treating a non-disposable lifetime manager as disposable, are there any issues with just implementing IDisposable, and checking to see if the inner manager also implements it during the disposal? In other words, doing something like the following:

public void Dispose()
{
    var disposableManager = _innerManager as IDisposable;

    if (disposableManager != null)            
        disposableManager.Dispose();                       
}
Aug 25, 2010 at 1:59 PM

I see that we now have HierarchicalLifetimeManager in Unity 2.0.

Can this somehow be used for the Per Request creating of Entity Framework's context or I am missing the point ?

Or we should use custom lifetime manages for the per request lifetime?

Aug 25, 2010 at 2:26 PM
rvukovic wrote:

I see that we now have HierarchicalLifetimeManager in Unity 2.0.

Can this somehow be used for the Per Request creating of Entity Framework's context or I am missing the point ?

Or we should use custom lifetime manages for the per request lifetime?

The purpose of this lifetime manager was so that you can register your IUnitOfWork etc in the main container using HierarchicalLifetimeManager.  Then for each request you create a child container, when something within that child container needs IUnitOfWork for the first time it will create it in the child container, every subsequent request will return the same instance.  This way you get the same behaviour as if you had registered IUnitOfWork as a ContainerControlledLifetimeManager in the child container, but in fact you registered it in the parent container.

 

Does that help?

 

Aug 25, 2010 at 2:44 PM
mrpmorris wrote:
The purpose of this lifetime manager was so that you can register your IUnitOfWork etc in the main container using HierarchicalLifetimeManager.  Then for each request you create a child container, when something within that child container needs IUnitOfWork for the first time it will create it in the child container, every subsequent request will return the same instance.  This way you get the same behaviour as if you had registered IUnitOfWork as a ContainerControlledLifetimeManager in the child container, but in fact you registered it in the parent container.

So I understood correctly the intention but I just can not band my mind from the example to the concrete usage.  Parent <-> child relation is confusing me, which one should I use.

Lets say I am using MVC 2 and I register:

    container.RegisterType< ....
                       
    var controllerFactory = new UnityControllerFactory(container);
    ControllerBuilder.Current.SetControllerFactory(controllerFactory);

I should then in the HttpApplication BeginRequest create Child controller with the Context/Session and then kill Child container at the EndRequest? I will try and see if this is working.

 


Aug 25, 2010 at 2:50 PM

Have a single container which is there for 2 purposes

 

1: To register everything that will exist in the child containers.

2: The contain services which should be shared across requests

Every request should be done in a child container.  If you are using ASP MVC (which it looks like you are) then I created an example

http://www.capableobjects.com/apps/InstantForum414/Topic5354-4-1.aspx

You'll need to download the object persistence framework ECO from http://www.capableobjects.com to use it.  The demo has less than 13 classes so you don't need a license.