From 08e4269495d523d9552d06f3e5702c1889d6a70d Mon Sep 17 00:00:00 2001 From: David Fowler Date: Wed, 7 Apr 2021 09:20:14 -0700 Subject: [PATCH] Disposing scopes more than once should work - Recently introduced a regression where disposing DI scopes multiple times throws. --- .../src/ServiceLookup/ServiceProviderEngineScope.cs | 6 ++++++ .../tests/DI.Tests/ServiceProviderEngineScopeTests.cs | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs index 656cf9b10c4f1f..b29b4016bc0f5b 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ServiceProviderEngineScope.cs @@ -176,6 +176,12 @@ private void ClearState() // try to return to the pool while somebody is trying to access ResolvedServices. lock (_scopeLock) { + // Don't attempt to dispose if we're already disposed + if (_state == null) + { + return; + } + // ResolvedServices is never cleared for singletons because there might be a compilation running in background // trying to get a cached singleton service. If it doesn't find it // it will try to create a new one which will result in an ObjectDisposedException. diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderEngineScopeTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderEngineScopeTests.cs index ae36f2e1d64bba..223c6bfd7bc8a9 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderEngineScopeTests.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderEngineScopeTests.cs @@ -21,6 +21,16 @@ public void ResolvedServicesAfterDispose_ThrowsObjectDispose() Assert.Throws(() => serviceProviderEngineScope.ResolvedServices); } + [Fact] + public void DoubleDisposeWorks() + { + var engine = new FakeEngine(); + var serviceProviderEngineScope = new ServiceProviderEngineScope(engine); + serviceProviderEngineScope.ResolvedServices.Add(new ServiceCacheKey(typeof(IFakeService), 0), null); + serviceProviderEngineScope.Dispose(); + serviceProviderEngineScope.Dispose(); + } + private class FakeEngine : ServiceProviderEngine { public FakeEngine() :