-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Breaking change: Throw when resolving on a disposed service provider #45116
Conversation
- Resolving Services after ServiceProvider is Disposed should throw with ObjectDisposedException
Tagging subscribers to this area: @eerhardt, @maryamariyan Issue Details
@davidfowl, for testing I took a test similar to the repro code you provided earlier in this comment Similar to the use case you were illustrating there where the singleton lock would be used, before this PR change, the test would result in a deadlock since Dispose would use the same "ResolvedServices" singleton lock when resolving singleton services. As shown in this test now it would throw ObjectDisposedException instead.
|
...ies/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderContainerTests.cs
Outdated
Show resolved
Hide resolved
…I.Tests/ServiceProviderContainerTests.cs
...ies/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs
Outdated
Show resolved
Hide resolved
...ies/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderContainerTests.cs
Outdated
Show resolved
Hide resolved
...ies/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs
Outdated
Show resolved
Hide resolved
...ies/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs
Outdated
Show resolved
Hide resolved
...ies/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs
Outdated
Show resolved
Hide resolved
...ies/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs
Outdated
Show resolved
Hide resolved
ac9f5fb
to
3931f61
Compare
Thanks @davidfowl. I think the PR is ready for another now. |
...ies/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs
Outdated
Show resolved
Hide resolved
...ies/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs
Outdated
Show resolved
Hide resolved
...ies/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderContainerTests.cs
Outdated
Show resolved
Hide resolved
5958ba2
to
bb079db
Compare
...ies/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs
Outdated
Show resolved
Hide resolved
bb079db
to
074800a
Compare
...ies/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs
Outdated
Show resolved
Hide resolved
...ies/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs
Outdated
Show resolved
Hide resolved
...ies/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs
Show resolved
Hide resolved
...ies/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderContainerTests.cs
Outdated
Show resolved
Hide resolved
...ies/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderContainerTests.cs
Outdated
Show resolved
Hide resolved
{ | ||
public Foo1() | ||
{ | ||
Thread.Sleep(5000); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this testing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If during resolve of this service, service provider gets disposed on another thread, the test asserts that we dispose of the service as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But the way the test is written above, this sleep will happen inline and then the object will be returned on line 276.
Once the object is returned, then you are starting a new thread to dispose the service provider.
So I don't think the sleep is doing anything beneficial.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, we need to kick off 2 threads.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If during resolve of this service, service provider gets disposed on another thread, the test asserts that we dispose of the service as well.
Removed this test and instead used tests below to also assert that the service (for both IDisposable and IAsyncDisposable cases) get disposed:
GetAsyncService_DisposeAsyncOnSameThread_ThrowsAndDoesNotHangAndDisposeAsyncGetsCalled
GetService_DisposeOnSameThread_ThrowsAndDoesNotHangAndDisposeGetsCalled
The removed case would have been very similar in outcome to the two test cases I mentioned above, so perhaps OK that we don't add it.
...ies/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderContainerTests.cs
Outdated
Show resolved
Hide resolved
...ies/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderContainerTests.cs
Outdated
Show resolved
Hide resolved
15a2f0b
to
90a2a98
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me. Nice work, @maryamariyan.
@davidfowl, for testing I prepared a test similar to the repro code you provided earlier in this comment
Similar to the use case you were illustrating there, this use case (before this PR change) would also result in a deadlock. Here we try to call Dispose while the singleton lock
ResolvedServices
is taken). As shown in this test now it would throw ObjectDisposedException instead.