Circular References with Dependency Injection
Dependency injection mechanisms carry the risk of unintentional circular references, which are not easy to detect or prevent. This topic describes the situations where you may inadvertently cause circular references to occur, resulting in a stack overflow and application error. The most common causes of circular references with dependency injection are the following:
- Objects generated through constructor injection that reference each other in their constructor parameters
- Objects generated through constructor injection where an instance of a class is passed as a parameter to its own constructor
- Objects generated through method call injection that reference each other
- Objects generated through property (setter) injection that reference each other
For example, the following code shows two classes that reference each other in their constructors.
public class Class1
{
public Class1(Class2 test2)
{ ... }
}
public class Class2
{
public Class2(Class1 test1)
{ ... }
}
Public Class Class1
Public Sub New(test2 As Class2)
...
End Sub
End Class
Public Class Class2
Public Sub New (test 1 As Class1)
...
End Sub
End Class
It is the responsibility of the developer to prevent this type of error by ensuring that the members of classes they use with dependency injection do not contain circular references.
Note
You could use constructor injection to specify any of a series of constructors or method overloads; however, you could inadvertently cause endless recursion. To avoid the endless recursion, specify which constructor to call in the RegisterType call.
Unity's default behavior is to resolve the constructor with the most parameters. This would cause endless recursion in the following example.
container.RegisterType<IServiceProvider, ServiceContainer>();
var sp = container.Resolve<IServiceProvider>();
container.RegisterType(Of IServiceProvider, ServiceContainer)()
Dim sp = container.Resolve(Of IServiceProvider)()
To avoid the endless recursion, specify which constructor to call in the RegisterType call, as in the following example:
container.RegisterType<IServiceProvider, ServiceContainer>(new InjectionConstructor());
container.RegisterType(Of IServiceProvider, ServiceContainer) _
(New InjectionConstructor())
In this case, when creating the service container, the zero argument constructor is explicitly requested.