When trying out the LightInject IoC container http://www.lightinject.net/ it throws a stackoverflow exception when resolving the type ISomeService:
All types are registered in App_Start:
container.RegisterAssembly("MyApp*.dll");
And then when I try to resolve it in the controller it fails and throws a stackoverflow exception:
public SomeController(ISomeService someService)
{
_someService = someService;
}
It also has the same error when using ServiceLocator:
ServiceLocator.Current.GetInstance<ISomeService>();
I have traced it through and I can see that it is failing in the LightInject ServiceContainer class right here, but I don't see why it is failing yet.
public object GetInstance(Type serviceType)
{
return GetDefaultDelegate(serviceType, true)(constants.Items);
}
After calling GetDefaultDelegate, the execution path ends back in GetInstance again, causing an infinite loop and a stack overflow.
EDIT 2 - Have tracked this down further and it appears to be caused by SomeService having both constructor and property injection at the same time:
public class SomeService : ISomeService
{
public IAnotherService AnotherService { get; set; }
public SomeService(IAnotherService anotherService)
{
AnotherService = anotherService;
}
}
The dependency IAnotherService AnotherService is being injected via the constructor and the property, but there was no intention to use property injectors.
EDIT 3
There are several layers in the app that all use ServiceLocator, so I initially added LI to its own project using NuGet, so I had:
MyApp.IoC.LightInject
MyApp.Repositories
MyApp.Services
MyApp.Web.UI
But it isn't actually necessary to add it to its own project because the service locator provider can be set in the UI layer:
var serviceLocator = new LightInjectServiceLocator(container);
ServiceLocator.SetLocatorProvider(() => serviceLocator);
So I have just now removed the extra project and put the NuGet packages into the UI layer instead. I've also installed LightInject.Annotation and deliberately not called the container.EnableAnnotatedPropertyInjection() method, to ensure that only constructor injection is used. It is still throwing a stackoverflow.
To test if the resolving is working I am just doing this in my HomeController.Index() method:
public ActionResult Index()
{
var a = ServiceLocator.Current.GetInstance<ISomeService>();
}
I added some console logging to the ServiceController.GetInstance methods so that I could see what the flow of method calls was that was leading to the stackoverflow. This is the log, and the results are a bit unexpected. You can see that when it calls CreateDelegate() for ISomeService that it ends up trying to get an instance of HomeController first - why is that?
DoGetInstance: ISomeService. Key = ''
GetInstance: ISomeService
TryGetValue: ISomeService not found
TryAddValue: trying to add ISomeService now
CreateDynamicMethodDelegate: ISomeService
CreateDynamicMethodDelegate: calling CreateDelegate() for ISomeService
DoGetInstance: HomeController. Key = ''
GetInstance: HomeController
TryGetValue: HomeController not found
TryAddValue: trying to add HomeController now
CreateDynamicMethodDelegate: HomeController
CreateDynamicMethodDelegate: calling CreateDelegate() for HomeController
DoGetInstance: ISomeService. Key = ''
GetInstance: ISomeService
TryGetValue: ISomeService not found
TryAddValue: trying to add ISomeService now
CreateDynamicMethodDelegate: ISomeService
CreateDynamicMethodDelegate: calling CreateDelegate() for ISomeService
DoGetInstance: HomeController. Key = ''
GetInstance: HomeController
TryGetValue: HomeController not found
TryAddValue: trying to add HomeController now
CreateDynamicMethodDelegate: HomeController
CreateDynamicMethodDelegate: calling CreateDelegate() for HomeController
DoGetInstance: ISomeService. Key = ''
GetInstance: ISomeService
TryGetValue: ISomeService not found
TryAddValue: trying to add ISomeService now
CreateDynamicMethodDelegate: ISomeService
CreateDynamicMethodDelegate: calling CreateDelegate() for ISomeService
DoGetInstance: HomeController. Key = ''
GetInstance: HomeController
TryGetValue: HomeController not found
TryAddValue: trying to add HomeController now
CreateDynamicMethodDelegate: HomeController
CreateDynamicMethodDelegate: calling CreateDelegate() for HomeController
DoGetInstance: ISomeService. Key = ''
GetInstance: ISomeService
TryGetValue: ISomeService not found
TryAddValue: trying to add ISomeService now
CreateDynamicMethodDelegate: ISomeService
CreateDynamicMethodDelegate: calling CreateDelegate() for ISomeService
When I comment out the service's constructor, the resolving works and all dependencies are resolved by property injection. If the constructor is included then it throws the stackoverflow exception.
And although the resolving ISomeService works when using properties only, I cannot resolve IAnotherService if that service includes ISomeService in its dependencies. I hope the log above will shed some light on the problem. The performance of LightInject so far has been significantly better than Unity