1
votes

When I dispose a Unity IoC container, how is the order Dispose() is called on singleton dependencies ( ContainerControlledLifetimeManager) determined? From my observations (and my expectations based on thinking about how it ought to work):

  • For objects added to the IoC using RegisterType(), dependencies are disposed in the reverse of the order in which they are Resolved at runtime.
  • For objects added to the IoC using RegisterInstance(), dependencies are disposed before those registered using RegisterType(), in reverse of the order in which they are resolved.

Can anyone confirm that I on the right track here? The rest of the internet seems pretty quiet on this topic, but if you can provide a link to a reference that spells this out explicitly, I'd really appreciate it. TIA!

1
RegisterInstance is used for registration of precreated (container uncontrolled) singletons. It seems unlikely to me that they are disposed before instances created with RegisterType, especially if those instances have a shorter lifestyle. In either case, I would expect that those precreated instances are disposed completely last (or even never, because the container didn't create them in the first place). - Steven
Thanks for the reply, Steven. Observations appear to contradict your (and formerly my) expectation. When both have ContainerControlledLifetimeManagers, RegisterInstance dependencies are, at least in my case, disposed before RegisterType dependencies. Or, possibly, dispose order is unrelated to how the dependencies get registered? Not sure. - Tim Trese

1 Answers

0
votes

Sorry for the late answer (it might help for others).

From my tests I can confirm that the container is disposed in reverse resolve order! So even if the registration happens via register instance, the dispose happens related to the resolve.

Instances that are not resolved are also disposed, but in an order that I can't predict!?

Test (object and interface declaration is missing):

var unityContainer = new UnityContainer();
unityContainer.RegisterInstance<IDisposableObject>("ObjUnused1", new DisposableObject("ObjUnused1"));
unityContainer.RegisterInstance<IDisposableObject>("Obj1", new DisposableObject("Obj1"));
unityContainer.RegisterType<IDisposableObject, DisposableObject>("Obj2", new ContainerControlledLifetimeManager(), new InjectionConstructor("Obj2"));
unityContainer.RegisterInstance<IDisposableObject>("Obj3", new DisposableObject("Obj3"));
unityContainer.RegisterType<IDisposableObject, DisposableObject>("Obj4", new ContainerControlledLifetimeManager(), new InjectionConstructor("Obj4"));
unityContainer.RegisterType<IDisposableSubObject, DisposableObject>(new ContainerControlledLifetimeManager(), new InjectionConstructor("Sub"));
unityContainer.RegisterType<IDisposableObjectWihSub, DisposableObjectWithSub>(new ContainerControlledLifetimeManager());
unityContainer.RegisterInstance<IDisposableObject>("ObjUnused2", new DisposableObject("ObjUnused2"));

var obj1 = unityContainer.Resolve<IDisposableObject>("Obj1");
var obj2 = unityContainer.Resolve<IDisposableObject>("Obj2");
var obj3 = unityContainer.Resolve<IDisposableObject>("Obj3");
var obj4 = unityContainer.Resolve<IDisposableObject>("Obj4");

var objWithSub = unityContainer.Resolve<IDisposableObjectWihSub>();
objWithSub.Label = "Master";

Console.WriteLine($"\r\nContainerContent:\r\n{unityContainer.DumpRegistrationLines()}");

Console.WriteLine();
unityContainer.Dispose();

Result:

Creation DisposableObject - ObjUnused1 (RegisterInstance)
Creation DisposableObject - Obj1       (RegisterInstance)
Creation DisposableObject - Obj3       (RegisterInstance)
Creation DisposableObject - ObjUnused2 (RegisterInstance)
Creation DisposableObject - Obj2       (RegisterType - via Resolve)
Creation DisposableObject - Obj4       (RegisterType - via Resolve)
Creation DisposableObject - Sub        (RegisterType - via Resolve)
Creation DisposableObjectWithSub -     (RegisterType - via Resolve)

ContainerContent before Disposal:
IUnityContainer          -> IUnityContainer           ContainerLifetimeManager Microsoft.Practices.Unity.IUnityContainer
IDisposableObject        -> IDisposableObject         Singleton Name:"ObjUnused1" Test.Entities.IDisposableObject
IDisposableObject        -> IDisposableObject         Singleton Name:"Obj1" Test.Entities.IDisposableObject
IDisposableObject        -> DisposableObject          Singleton Name:"Obj2" Test.Entities.DisposableObject
IDisposableObject        -> IDisposableObject         Singleton Name:"Obj3" Test.Entities.IDisposableObject
IDisposableObject        -> DisposableObject          Singleton Name:"Obj4" Test.Entities.DisposableObject
IDisposableObject        -> IDisposableObject         Singleton Name:"ObjUnused2" Test.Entities.IDisposableObject
IDisposableSubObject     -> DisposableObject          Singleton Test.Entities.DisposableObject
IDisposableObjectWihSub  -> DisposableObjectWithSub   Singleton Test.Entities.DisposableObjectWithSub

Disposing:
Disposal DisposableObject - ObjUnused2
Disposal DisposableObjectWithSub - Master
Disposal DisposableObject - Sub
Disposal DisposableObject - Obj4
Disposal DisposableObject - Obj3
Disposal DisposableObject - Obj2
Disposal DisposableObject - Obj1
Disposal DisposableObject - ObjUnused1

Conclusion: the container does a good job when disposing!