You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As noted in an ignored integration test: BoDi.Tests.RegisterFactoryDelegateTests.ShouldThrowExceptionForDynamicCircuarDepenencies - if a factory delegate registers a component and makes use of a resolved IObjectContainer inside of the registration, circular dependencies are not detected if they exist in the resolved objects.
Here, we have two 'resolutions' occurring. An outer resolution - in which the container resolves a factory registration for ClassWithCircularDependency1 and an inner resolution in which the container resolves an unregistered type for ClassWithCircularDependency2.
Root cause analysis
The root cause of this is that when resolving an IObjectContainer and using this to dynamically resolve dependencies, that inner resolve operation does not have access to the "resolution path" information of the outer resolution operation. This thwarts circular dependency detection because the resolution path chain is repeatedly broken and started again from fresh, and never comes full circle.
The resolution path looks like:
We begin with the outer resolve operation's resolution path:
ClassWithCircularDependency1
IObjectContainer
Then a new resolve operation - the inner one - begins a new resolution path
ClassWithCircularDependency2
ClassWithCircularDependency1
IObjectContainer
Another new inner resolve operation begins, using a new path, and another, and another until the stack overflows
Proposed solution (overview)
I have a solution for this - which is that when resolving an IObjectContainer and the object container is not the very first thing in the resolution path, then instead of resolving and returning the real object container, instead return an instance of a proxy class which also implements the same interface (and contains the real container as a private field). That same proxy type would also receive the "resolution path" information from the parent/outer resolution operation.
Within the proxy type, most calls may just be proxied wholesale, but calls to resolve things would instead use a resolve method which passes on that resolution path information. Thus the continuity of the 'overall' resolve operation (the outer and the inner) is preserved. Thus there is only ever one resolution path in play and it looks like so:
ClassWithCircularDependency1
IObjectContainer
ClassWithCircularDependency2
ClassWithCircularDependency1
At this stage, circular dependency detection may trigger and raise an exception, because ClassWithCircularDependency1 appears twice in the path.
Where to find an implementation
As a project of my own, I have forked BoDi. I have fixed this very same problem in that project but it's diverged so much that it would be impossible to do a simple back-port of the fix into BoDI. Indeed, I've since archived that forked repo in order to create a new non-forked one.
However, you can find my fix in this this issue in that archived repo. The relevant commits should all be findable from the issue.
The text was updated successfully, but these errors were encountered:
As noted in an ignored integration test: BoDi.Tests.RegisterFactoryDelegateTests.ShouldThrowExceptionForDynamicCircuarDepenencies - if a factory delegate registers a component and makes use of a resolved
IObjectContainer
inside of the registration, circular dependencies are not detected if they exist in the resolved objects.Example
Here's the example from that integration test:
Here, we have two 'resolutions' occurring. An outer resolution - in which the container resolves a factory registration for
ClassWithCircularDependency1
and an inner resolution in which the container resolves an unregistered type forClassWithCircularDependency2
.Root cause analysis
The root cause of this is that when resolving an
IObjectContainer
and using this to dynamically resolve dependencies, that inner resolve operation does not have access to the "resolution path" information of the outer resolution operation. This thwarts circular dependency detection because the resolution path chain is repeatedly broken and started again from fresh, and never comes full circle.The resolution path looks like:
Proposed solution (overview)
I have a solution for this - which is that when resolving an
IObjectContainer
and the object container is not the very first thing in the resolution path, then instead of resolving and returning the real object container, instead return an instance of a proxy class which also implements the same interface (and contains the real container as a private field). That same proxy type would also receive the "resolution path" information from the parent/outer resolution operation.Within the proxy type, most calls may just be proxied wholesale, but calls to resolve things would instead use a resolve method which passes on that resolution path information. Thus the continuity of the 'overall' resolve operation (the outer and the inner) is preserved. Thus there is only ever one resolution path in play and it looks like so:
At this stage, circular dependency detection may trigger and raise an exception, because
ClassWithCircularDependency1
appears twice in the path.Where to find an implementation
As a project of my own, I have forked BoDi. I have fixed this very same problem in that project but it's diverged so much that it would be impossible to do a simple back-port of the fix into BoDI. Indeed, I've since archived that forked repo in order to create a new non-forked one.
However, you can find my fix in this this issue in that archived repo. The relevant commits should all be findable from the issue.
The text was updated successfully, but these errors were encountered: