I'm seeing some unexpected behaviour in Unity when registering and resolving IServiceLocator
using the HierarchicalLifetimeManager
.
What I'm seeing suggests that Unity treats the concrete type UnityServiceLocator
as a special case when you register it. It treats the type as a static singleton, even when it shouldn't. This behaviour seems to be particular to UnityServiceLocator
.
Background: I am slowly phasing out the "static" ServiceLocator
in a few places in our code where it exists. The first step was going to be to register IServiceLocator
in Unity and then have it injected as a dependency into those classes that use it.
In the following code, I register an injection factory to create a new instance of UnityServiceLocator
. I also scope it with HierarchicalLifetimeManager
to give me one instance per child container:
private static void Main(string[] args)
{
var container = new UnityContainer();
container.RegisterType<IServiceLocator>(
new HierarchicalLifetimeManager(),
new InjectionFactory(
c =>
{
Console.WriteLine("InjectionFactory invoked with container: " + c.GetHashCode());
return new UnityServiceLocator(c);
}));
container.Resolve<IServiceLocator>(); // expect to see console output here
container.Resolve<IServiceLocator>(); // don't expect to see console output here
var child = container.CreateChildContainer();
child.Resolve<IServiceLocator>(); // expect to see console output here
container.Resolve<IServiceLocator>(); // don't expect to see console output here
var anotherChildContainer = container.CreateChildContainer();
anotherChildContainer.Resolve<IServiceLocator>(); // expect to see console output here
anotherChildContainer.Resolve<IServiceLocator>(); // don't expect to see console output here
}
I would expect the above code to invoke the factory, create the UnityServiceLocator
instance and write out console output three times, once for each container.
It doesn't - it does it once, as if I'd registered it as a singleton:
InjectionFactory invoked with container: 20903718
It gets worse:
If I now make my own class implement IServiceLocator
(literally, implement the interface, one ctor which takes IUnityContainer
, and have all methods throw NotImplementedException
), and swap the line
return new UnityServiceLocator(c);
with
return new MyUnityServiceLocator(c);
This starts behaving the way I'd expect:
InjectionFactory invoked with container: 20903718
InjectionFactory invoked with container: 51746094
InjectionFactory invoked with container: 41215084
I just cannot understand this behaviour unless Unity treats UnityServiceLocator
as a special case.
Does anyone have any other explanation for this behaviour? Am I missing something obvious, or is Unity internally treating UnityServiceLocator as a special case and ignoring the lifetime strategy I am specifying?
It turns out that UnityServiceLocator
is a special case - it registers itself with ExternallyControlledLifetimeManager
in it's own constructor when it is first created.
See Randy Levy's comment here for more information: unity.codeplex.com/workitem/12727