ContainerControledLifetimeManager -> not singleton?

Jul 20, 2013 at 12:43 PM
Hi,

I have a little problem on understanding, how to resolve a Instance as a singleton.

I am registering a class with the unity container which realizes three different interfaces.
I am registering this class in all three cases using the ContainerControledLifetimeManager.
this.Container.RegisterType<IRunableComponent, StatusMonitor>(ComponentNames.StatusMonitor, new ContainerControlledLifetimeManager());
            this.Container.RegisterType<IEbc, StatusMonitor>(ComponentNames.StatusMonitor, new ContainerControlledLifetimeManager());
            this.Container.RegisterType<IStatusMonitor, StatusMonitor>(new ContainerControlledLifetimeManager());
If I resolve my StatusMonitor like:
var components = this.container.ResolveAll<IRunableComponent>().ToList();
            var ebcs = this.container.ResolveAll<IEbc>().ToList();
            var statusMonitor = this.container.Resolve<IStatusMonitor>();
I get the same instance for the both ResolveAll (StatusMonitorConstructor is called only once)
but I get a addional new instance for the last Resolve.

What is it I am doing wrong?

Thanks for hints and help!
Regards
Rainer
Editor
Jul 20, 2013 at 3:03 PM
What behavior are you expecting (or wanting) to see? Do you only want one instance of StatusMonitor no matter the registration (singleton) or do you want each registration to have its own singleton (actually a Multiton?

Here's what is happening: when performing a resolve of an interface Unity first maps the interface to a type and name (BuildKey). Once the type mapping is performed all injection (including lifetime management) is based on the implementation class (and registration name). So, you get the same instance for the named registration and a different instance for the unnamed registration. If you want once instance then the easiest way is to use one build name (or the default unnamed) for all registrations involving that type.

If you want a singleton across named and unnamed registration you probably have to use RegisterInstance but this has the potential downside of calling dispose multiple times and you would have to resolve after all dependencies are registered. Another alternative would be to implement an actual singleton and register that with the container.

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
Jul 20, 2013 at 3:27 PM
Hello Randy,

thank you very much for your detailed answer!

I would like it to be the way, that my StatusMonitor component is a singleton.
This component realizes a couple of Interfaces:
IEbc -> the component is a "EventBasedComponent"
IRunnable -> the component has "Start,Stop,Pause,Continue"
IStatusMonitor -> well, the specific component interface

In my project I have a bunch of such components, of wich I must get hold of at different places as IEbc and IRunable that is where I use the ResolveAll which works as expected.
Only my "StatusViewModel" needs to get hold of IStatusMonitor, this is where I would like to use Resolve<IStatusMonitor>

The problem with the following way of Registration is:
this.Container.RegisterType<IRunableComponent, StatusMonitor>(ComponentNames.StatusMonitor, new ContainerControlledLifetimeManager());
            this.Container.RegisterType<IEbc, StatusMonitor>(ComponentNames.StatusMonitor, new ContainerControlledLifetimeManager());
            this.Container.RegisterType<IStatusMonitor, StatusMonitor>(ComponentNames.StatusMonitor, new ContainerControlledLifetimeManager());
That if I want to resolve the IStatusMonitor in my viewmodel by:
var statusMonitor = this.container.Resolve<IStatusMonitor>();
I get the ErrorMessage shown below. This is only if I use the registration <IStatusMonitor,StatusMonitor>(<name>,liftetimemanager).
If i don't use the "name" it works, but I get a new instance what makes it no longer a singleton.
My current solution is to query the IStatusMonitor form all IEbc but this can only be a workaround. I would prefere to do it the right way ;-)

Regards
Rainer

Microsoft.Practices.Unity.ResolutionFailedException was unhandled by user code
HResult=-2146233088
Message=Resolution of the dependency failed, type = "Qutronic.BfpNetR2.Common.Interfaces.IStatusMonitor", name = "(none)".
Exception occurred while: while resolving.

Exception is: InvalidOperationException - The type IStatusMonitor does not have an accessible constructor.

At the time of the exception, the container was:

Resolving Qutronic.BfpNetR2.Common.Interfaces.IStatusMonitor,(none)

Source=Microsoft.Practices.Unity
TypeRequested=IStatusMonitor
StackTrace:
   bei Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable`1 resolverOverrides)
   bei Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, String name, IEnumerable`1 resolverOverrides)
   bei Microsoft.Practices.Unity.UnityContainer.Resolve(Type t, String name, ResolverOverride[] resolverOverrides)
   bei Microsoft.Practices.Unity.UnityContainerExtensions.Resolve[T](IUnityContainer container, ResolverOverride[] overrides)
   bei Qutronic.BfpNetR2.Gui.SimpleTestVfp.ViewModels.StatusViewModel.HookupToStatusMonitor() in d:\Daten\Softwareentwicklung\Projekte\BfpNetR2\3_Entwicklung\Source\Main\BfpNetR2\SimpleTestVfp\ViewModels\StatusViewModel.cs:Zeile 86.
   bei Qutronic.BfpNetR2.Gui.SimpleTestVfp.ViewModels.StatusViewModel..ctor(IUnityContainer container) in d:\Daten\Softwareentwicklung\Projekte\BfpNetR2\3_Entwicklung\Source\Main\BfpNetR2\SimpleTestVfp\ViewModels\StatusViewModel.cs:Zeile 42.
   bei lambda_method(Closure , IBuilderContext )
   bei Microsoft.Practices.ObjectBuilder2.DynamicBuildPlanGenerationContext.<>c__DisplayClass1.<GetBuildMethod>b__0(IBuilderContext context)
   bei Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context)
   bei Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context)
   bei Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context)
InnerException: System.InvalidOperationException
   HResult=-2146233079
   Message=The type IStatusMonitor does not have an accessible constructor.
   Source=Microsoft.Practices.Unity
   StackTrace:
        bei Microsoft.Practices.ObjectBuilder2.DynamicMethodConstructorStrategy.ThrowForNullExistingObject(IBuilderContext context)
        bei lambda_method(Closure , IBuilderContext )
        bei Microsoft.Practices.ObjectBuilder2.DynamicBuildPlanGenerationContext.<>c__DisplayClass1.<GetBuildMethod>b__0(IBuilderContext context)
        bei Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context)
        bei Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context)
        bei Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context)
        bei Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable`1 resolverOverrides)
   InnerException: 
Editor
Jul 20, 2013 at 4:38 PM
Since you are registering a named instance:
this.Container.RegisterType<IStatusMonitor, StatusMonitor>(ComponentNames.StatusMonitor, new ContainerControlledLifetimeManager());
You will need to resolve a named instance:
var statusMonitor = this.container.Resolve<IStatusMonitor>(ComponentNames.StatusMonitor);
Since you are using the same registration name you will get the same instance.

If you want a combination of unnamed registrations and named registration then you could use RegisterInstance but subject to the potential issues I mentioned previously:
    this.Container.RegisterType<IRunableComponent, StatusMonitor>
        (ComponentNames.StatusMonitor, new ContainerControlledLifetimeManager());
    this.Container.RegisterType<IEbc, StatusMonitor>
        (ComponentNames.StatusMonitor, new ContainerControlledLifetimeManager());
    this.Container.RegisterInstance<IStatusMonitor>(
        ((IStatusMonitor)this.Container.Resolve<IRunableComponent>(ComponentNames.StatusMonitor)));
~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
Jul 21, 2013 at 3:41 AM
Hello Randy,

thank you very much for your help!
You will need to resolve a named instance:
Was the missing information for me. Now things work as I need them :-)

Regards
Rainer