Inconsistent Behavior: HierarchicalLifetimeManager/Generic Type

Jun 4, 2011 at 2:28 PM
Edited Jun 4, 2011 at 2:43 PM

I am using Unity in code that models the repository and unit of work patterns.  I am using unity to dependency inject the business component to the repositories and overall pleased with Unity but I have found an odd behavior that is giving me issues in my design.  Below I created a simple example that reproduces the issue.  While this is obviously not the actual code it shows the issue I am seeing in its simplest form.  What I am seeing is as follows:

  • I create a container with a type registration.  The type being registered is generic interface.
  • I want to use the InjectionFactory class since I need to provide some logic that needs to execute when creating the concrete type.
  • The HierarchicalLifetimeManager is specified.
  • Next, I create multiple child containers since I want to be able to easily dispose all instantiated objects that were created for a given child container.

Below in the code, I indicate the issue I am seeing in the use of the *first* created child container.  For each container, my understanding is that the InjectionFactory should be called ONCE for each instance created on a given child container.  This IS the case for the second, third, .... child containers, but the first child container does not behave the same as all the others and this is what is giving us issues.

From putting this code together, I have found:

  • It appears to only happen when registering generic types
  • It appears to only happen when using the HierarchicalLifetimeManager
  • All child containers created after the first appear to work as expected.
  • The line with the inconsistent behavior is indicated below with #### and also by a failing unit-test that should pass.

Below is the sample code example.   I hope someone can help me with this as I would like to continue using Unity as my DI container and not another open-source one.  I am hoping that this bug that can be easily addressed.

Thanks in advance for any assistance.

 

[TestClass]
    public class UnityIssueTest2
    {
        [TestMethod]
        public void IssueTest()
        {
            IUnityContainer container = new UnityContainer();

            container.RegisterType(
                typeof(ISomeInterface<>),
                new HierarchicalLifetimeManager(),
                new InjectionFactory((c, t, s) =>
                    {
                        Type ct = typeof(SomeConcreteType<>);
                        Type gct = ct.MakeGenericType(typeof(int));

                        return Activator.CreateInstance(gct);  // ** Set breakpoint here
                    }));

            IUnityContainer childContainer = container.CreateChildContainer();
            var o1 = childContainer.Resolve<ISomeInterface<int>>();  // LINE ** Breakpoint hits(I would expect - first instance created for child container) **
            var o2 = childContainer.Resolve<ISomeInterface<int>>();  // LINE ** Breakpoint hits(I would NOT expect - instance should have been reused) #### ** 
            var o3 = childContainer.Resolve<ISomeInterface<int>>();  // LINE ** Breakpoint does *not* hit(I would expect - instance already created for child container so reused.) **

            Assert.AreSame(o1, o2);  // this Assert Fails.

            IUnityContainer childContainer2 = container.CreateChildContainer();
            var o4 = childContainer2.Resolve<ISomeInterface<int>>(); // LINE ** Breakpoint hits(I would expect - first instance for new child container) **
            var o5 = childContainer2.Resolve<ISomeInterface<int>>(); // LINE ** Breakpoint does *not* hit(I would expect - instance already created for child container so reused.) **
            var o6 = childContainer2.Resolve<ISomeInterface<int>>(); // LINE ** Breakpoint does *not* hit(I would expect - instance already created for child container so reused.) **

            Assert.AreSame(o4, o5);
        }




    }

    public interface ISomeInterface<T>
    {
    }

    public class SomeConcreteType<T> : ISomeInterface<T>
    {
    }
Jun 6, 2011 at 2:40 PM

We'll check this out and get back to you on this.

Gino Terrado
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Jun 7, 2011 at 3:27 AM

Hi,

We were able to reproduce your scenario. After some investigation, we found out that it works fine when we removed the InjectionFactory. Also, we found out that resolving the parent container first before child containers will eliminate the issue. This could be the possible workaround as of now.

 

Noel Angelo Bolasoc
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Jun 7, 2011 at 1:02 PM

Could you please elaborate on how I would go about resolving the parent container? I will try both of these options. Is this a bug that is going to be resolved in a future release so I can remove the work-around at a later date?


From: [email removed]
To: [email removed]
Date: Mon, 6 Jun 2011 19:27:59 -0700
Subject: Re: Inconsistent Behavior: HierarchicalLifetimeManager/Generic Type [unity:260188]

From: AvanadeSupport
Hi,
We were able to reproduce your scenario. After some investigation, we found out that it works fine when we removed the InjectionFactory. Also, we found out that resolving the parent container first before child containers will eliminate the issue. This could be the possible workaround as of now.

Noel Angelo Bolasoc
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com
Read the full discussion online.
To add a post to this discussion, reply to this email (unity@discussions.codeplex.com)
To start a new discussion for this project, email unity@discussions.codeplex.com
You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.
Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com
Jun 7, 2011 at 6:32 PM

A followup to this issue.  The second workaround is not an option since the type being registered is an open generic type.  This would require that every possible type that that would provide a closure would have to be resolved.  I still like Unity as a DI container when compared to other options but I tend to believe that this is a major issue given that it is key to the correct operation of applications that utilize Unity.

Jun 8, 2011 at 2:59 AM

Hi,

Unfortunately, that would be the only workaround I can think of right now. I'm just thinking that this would be the same effort as you would do during the registration since you are mapping an open generic type to a closed generic type (In your example, ISomeInterface<> to SomeConcreteType<int>). You still need to do another registration if you want to map to a closed generic of another type. I'm aware that you already logged this to our issue tracker so lets just wait for Microsoft's feedback regarding on this.

 

Noel Angelo Bolasoc
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Jun 15, 2011 at 3:52 PM

Thanks for the assistance.  I refactored my design to make it better and was able to avoid the issue completely.  I am writing the following in case anyone else can benefit from my learning experience.  I am working on an implementation of the Repository and Unit-of-work patterns sitting on top of Entity Framework 4.0.  My unit of work wraps the Entity Framework data context and was registered as an open generic type.  For the other components such as the repositories and business components, I had the developer specify the mapping to register with the container.  When running in a non-testable mode I want Unity to dependency-inject all of the object references and when following TDD have the developer specify known mocks.  Having the developer manually register the business components, repositories, and unit of work objects I felt could have been automated when running the application outside of unit testing.  So what I did was allow the user to specify a set of classes that indicate a list of assembles and a method that is called that determines what types from those assemblies that should be registered by using reflection.  So all I had to do was find all types that implement IContext then register a *closed* IUnitOfWork<> for that given context type.  This makes the issue go away since I am registering a closed generic type.  The construction of the container is only initiated once on start up.  I am also no longer using a child container but using a custom lifetime manager that stores the object references in the current request's context.  I was creating the child container per-request so all object instances could be maintained by the child container for that request so they could be easily disposed.  Using a custom lifetime manager based on the HTTP context, since this is a web application, allowed me to expose a static dispose method that is invoked on completion of the request that disposed all object added to the current request's context wrapped by the custom lifetime manager if they implement IDisposable.  So in the end, the original issue has been avoided and I feel I have a much better design.