ChildContainer strange behaviour

Jan 27, 2010 at 2:38 PM

Hi everyone. When working with Unity I've encountered some wrong behaviour of Unity

I configure my containers using app.config which you will find below:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    <section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
  </configSections>
  <unity>
    <typeAliases>
      <typeAlias alias="I" type="Unity1.Host.ISomeInterface, Unity1.Host" />
      <typeAlias alias="C" type="Unity1.Host.SomeClass, Unity1.Host" />
    </typeAliases>
    <containers>
      <container>
        <types>
          <type type="I" mapTo="C" />
        </types>
      </container>
      <container name="ModuleName">
        <types>
          <type type="I" mapTo="C">
            <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, 
                                       Microsoft.Practices.Unity.Configuration">
              <constructor>
                <param name="values" parameterType="System.String[]">
                  <array>
                    <value value="ModuleName" type="System.String" />
                    <value value="ModuleName" type="System.String" />
                    <value value="ModuleName" type="System.String" />
                  </array>
                </param>
              </constructor>
            </typeConfig>
          </type>
        </types>
      </container>
    </containers>
  </unity>
</configuration>
When I run this code:
namespace Unity1.Host
{
    internal class Program
    {
        private static UnityConfigurationSection _configuration;

        private static void Main(string[] args)
        {
            Console.WriteLine("Start Host");

            _configuration = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
            IUnityContainer root = new UnityContainer();
            _configuration.Containers.Default.Configure(root);

            IUnityContainer child = root.CreateChildContainer();
            _configuration.Containers["ModuleName"].Configure(child);

            ISomeInterface obj1 = root.Resolve<ISomeInterface>();
            Console.WriteLine(obj1.Count());

            Console.WriteLine();

            ISomeInterface obj = child.Resolve<ISomeInterface>();
            Console.WriteLine(obj.Count());

            Console.WriteLine("Press any key ...");
            Console.ReadKey();
        }
    }

    public interface ISomeInterface
    {
        int Count();
    }

    internal class SomeClass : ISomeInterface
    {
        private string[] _values = null;

        public SomeClass(string[] values)
        {
            _values = values;
        }

        public int Count()
        {
            return null == _values ? 0 : _values.Length;
        }
    }
}

... than I get:
Start Host
0
0
Press any key ...
Question: Why did i receive 0 from a SomeClass resolved by a child container? 
Shouldn't the child container be configured for ISomeInterface with the SomeClass constructor injected with 2 element array of string?
Shouldn't the second 0 be 2?
Please help because i'm confused now.

 

Jan 29, 2010 at 1:37 AM

I have a theory that it's a bug. Could you do me a favor? If you reverse the order of your resolve calls (resolve through the child before the parent) does it give you the right answer?

If it does, then my theory is correct.

 

Jan 29, 2010 at 9:30 AM

We have tested it with the reversed order and then everything was fine.

Feb 1, 2010 at 1:14 AM
Edited Feb 1, 2010 at 1:16 AM

What exactly is happening there Chris? I'm curious to know...

Will this be fixed in the next version?

Feb 1, 2010 at 5:11 PM

Basically, what's happening is this: internal to Unity is a data structure called the PolicyList. This stores everything we look up by type: lifetime managers, type configuration, and so forth. PolicyLists have a hierarchical organization. If you ask for a policy and it's not there, it'll ask it's parent policy list, and so on until the request is answered or the policy's not found at all.

One such policy is the build plan. This is, in a nutshell, the dynamically created method we build to create objects.

Here's what's happening. When you resolve from the parent first, it creates the build plan. This bakes in the parameters that were configured into the build plan. Then when you resolve through the child, it doesn't have a build plan, but the parent does, so it uses that one.

When you resolve through the child first, it creates the build plan according to it's own configuration. The plan is then stored in the policy list local to the child container. This doesn't affect the parent container, so everything works as expected.

The obvious fix would be never to look up to the parent for build plans, but this could break other stuff that also creates build plans. The factory stuff is the biggest one here; if you configure a factory in the parent, you want it to flow down to the child unless overridden. Either way is non-obvious behavior,.

I'm not going to promise a fix for Unity 2.0, although I'll be thinking about it very hard. There's some serious subtleties, and this behavior has been in there since Unity 1.0. Since this is the first report I've heard of this issue, doesn't sound like it's hurting too many users. There's a reasonable workaround - don't do that. :-) Basically, don't resolve anything in the parent.

Parent / child containers have a number of issues like this which need some revisiting.

 

Feb 1, 2010 at 6:08 PM

Thanks for the answer, a cruel one :) but I hope you'll make it till Unity 2.0

Keep up doing good work!

Feb 2, 2010 at 6:30 AM

Hi Chris

I'am just thinking out loud...

is it perhabs possible to create a Build Plan Policy each time a mapping is registred within the container. And just mark it as "not built" or something like that. So if you register a mapping in the root container and in a child container. Resolve them first on the root and then on the child there already exist a build plan policy in the child container.... but it is not realy "built".

I didn't verified it, but it perhaps solves the problem described. What is your opinion?

 

Marco

 

 

Feb 2, 2010 at 7:51 PM

I've been thinking along these lines myself. What gets in the way is Unity's "we can resolve it even if it's not registered" feature.

Don't get me wrong, I'd very much like to fix this (and a couple other nasties around child containers and build plans). I just can't promise the fix will be done in time for 2.0.