New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ExternalRegistrySource reuses ExternalComponentRegistration instances causing ObjectDisposedException #960
Comments
Okay here is what I see:
I do not understand why the other 10 registrations here are being disposed of (as they are registered in childScope/rootScope not actionScope and the same instances later used again for other actionScopes). I write my train of thought:
But no it does not? Take a look at this screenshot: The registration for How/why does this activator get shared between the two registrations in entirely different scopes? The registration for this type is made on the rootScope. |
Oh, I see it.
This means that my actionScope's registry reuses the And then when the deeper scope is disposed, the registration instance is disposed of, even though it remains in use in the grandparent! That's not right. |
I have the same problem after upgrading to 4.9.0 (4.8.X works fine) (was waiting for #218 to use contextual loggers) I was able to reproduce it using this sample : Edit |
Looks like #946 (included in 4.9.0) made it visible by throwing the exception, although the use-after-dispose was already happening (silently) in earlier versions. |
Thank you @sandersaares and @chenmach for the help. Looks like something that crept in under the radar a while ago. I added a few more assertions to the unit test from @sandersaares and confirmed the issue fixes the scenario in the Gist from @chenmach. |
I have released |
Edit: updated issue description here. Original below and in comments.
Consider a three-level lifetime scope hierarchy:
Register type T in
root
with InstancePerLifetimeScope.Register some irrelevant types in
middle
and inchild
(to materialize a scope-specific registry and not reuse the copy-on-write registry).Now resolve type T from
middle
. This results in a newExternalComponentRegistration
being added to the registry ofmiddle
, based on the registration inroot
.Now resolve type T from
child
. This results in the same instance ofExternalComponentRegistration
being added to the registry ofchild
as was added tomiddle
.Now dispose of
child
. The registration still shared withmiddle
is disposed of!Now attempt to resolve T from
middle
. You get ObjectDisposedException from the activator.The root cause is that
ExternalRegistrySource.RegistrationsFor
will reuse existing instances from the parent if they are already ExternalComponentRegistrations.Proposed fix: do not reuse instances of
ExternalComponentRegistration
.I am trying to debug a registration disposal issue and request hints at what to look at, so I could properly analyze the situation and formulate a sensible bug report (or discover my error).
The situation is:
I have a root scope and a child scope. Neither is disposed. I am resolving from the child scope.
The failure appears to be when resolving my type T that has a parameter of type
ILifetimeScope
(used by my object T to create child scopes). The registration forILifetimeScope
hasIsDisposed=true
(looking in childScope.ComponentRegistry.Registrations).In fact, registrations for all types inherited via
InstancePerLifetimeScope()
from my root scope are alsoIsDisposed=true
. One registration that is defined directly on the child scope isIsDisposed=false
.Example of registering a type on the root scope (registration IsDisposed=true when exception occurs)
Example of creating child scope and registering a type on it (registration IsDisposed=false):
I later create a next layer child scope and try to resolve:
JobExecutionAttempt
takes parameter of typeILifetimeScope
which triggers ObjectDisposedException in .Resolve().I do not expect you to have a solution for me based on this meager info but I request input on what I should be looking at. It is very much unexpected to me that ILifetimeScope and inherited registrations are IsDisposed=true. What can cause registrations to be IsDisposed=true without the lifetime scope being disposed?
This seems to happen after some time - not on the first entry into the last using block but perhaps the second?
I will continue to dig and improve the issue report once I find more relevant data.
The text was updated successfully, but these errors were encountered: