From 3111b1a42e053247af63ca9c6149f6a473a1bb9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rkstr=C3=B6m?= Date: Sun, 25 Apr 2021 23:27:12 +0300 Subject: [PATCH 1/8] Adds extension method to create service scope that implements IAsyncDisposable. - Introduces a new type AsyncServiceScope that implements IServiceScope and IAsyncDisposable. The type just wraps an existing IServiceScope instance, which it tries to cast it to an IAsyncDisposable when DisposeAsync is called. - Adds netstandard2.1 target to avoid bringing in System.Threading.Tasks.Extensions and Microsoft.Bcl.AsyncInterfaces if not needed. - Fixes #43970 --- ...nsions.DependencyInjection.Abstractions.cs | 10 ++++ ...ns.DependencyInjection.Abstractions.csproj | 7 ++- .../src/AsyncServiceScope.cs | 51 +++++++++++++++++++ ...ns.DependencyInjection.Abstractions.csproj | 8 ++- .../src/ServiceProviderServiceExtensions.cs | 10 ++++ 5 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs index 6b52486993922..7370f2cc4b6f8 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs @@ -19,6 +19,15 @@ public partial class ActivatorUtilitiesConstructorAttribute : System.Attribute { public ActivatorUtilitiesConstructorAttribute() { } } + public struct AsyncServiceScope : Microsoft.Extensions.DependencyInjection.IServiceScope, System.IAsyncDisposable + { + public AsyncServiceScope(Microsoft.Extensions.DependencyInjection.IServiceScope serviceScope) + { + } + public System.IServiceProvider ServiceProvider { get { throw null; } } + public void Dispose() { } + public System.Threading.Tasks.ValueTask DisposeAsync() { throw null; } + } public partial interface IServiceCollection : System.Collections.Generic.ICollection, System.Collections.Generic.IEnumerable, System.Collections.Generic.IList, System.Collections.IEnumerable { } @@ -106,6 +115,7 @@ public enum ServiceLifetime } public static partial class ServiceProviderServiceExtensions { + public static Microsoft.Extensions.DependencyInjection.AsyncServiceScope CreateAsyncScope(this System.IServiceProvider provider) { throw null; } public static Microsoft.Extensions.DependencyInjection.IServiceScope CreateScope(this System.IServiceProvider provider) { throw null; } public static object GetRequiredService(this System.IServiceProvider provider, System.Type serviceType) { throw null; } public static T GetRequiredService(this System.IServiceProvider provider) where T : notnull { throw null; } diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.csproj b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.csproj index 6b74303de9eec..f85823f03e54c 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.csproj +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.csproj @@ -1,6 +1,6 @@ - netstandard2.0;net461 + netstandard2.1;netstandard2.0;net461 enable @@ -8,4 +8,9 @@ + + + + diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs new file mode 100644 index 0000000000000..c44842b46d9be --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Threading.Tasks; + +namespace Microsoft.Extensions.DependencyInjection +{ + /// + /// A implementation that implements . + /// + public struct AsyncServiceScope : IServiceScope, IAsyncDisposable + { + private readonly IServiceScope _serviceScope; + + /// + /// Initializes a new instance of the struct. + /// Wraps an instance of . + /// The instance to wrap. + /// + public AsyncServiceScope(IServiceScope serviceScope) + { + if (serviceScope is null) + { + throw new ArgumentNullException(nameof(serviceScope)); + } + + _serviceScope = serviceScope; + } + + /// + public IServiceProvider ServiceProvider => _serviceScope.ServiceProvider; + + /// + public void Dispose() + { + _serviceScope.Dispose(); + } + + /// + public ValueTask DisposeAsync() + { + if (_serviceScope is IAsyncDisposable ad) + { + return ad.DisposeAsync(); + } + _serviceScope.Dispose(); + return default; + } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Microsoft.Extensions.DependencyInjection.Abstractions.csproj b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Microsoft.Extensions.DependencyInjection.Abstractions.csproj index 65d3953595f06..c7ac4d7c6380a 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Microsoft.Extensions.DependencyInjection.Abstractions.csproj +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Microsoft.Extensions.DependencyInjection.Abstractions.csproj @@ -1,7 +1,7 @@ - netstandard2.0;net461 + netstandard2.1;netstandard2.0;net461 true enable @@ -14,4 +14,10 @@ + + + + + diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceProviderServiceExtensions.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceProviderServiceExtensions.cs index c30b867c4a392..ff6a16e08165e 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceProviderServiceExtensions.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceProviderServiceExtensions.cs @@ -125,5 +125,15 @@ public static IServiceScope CreateScope(this IServiceProvider provider) { return provider.GetRequiredService().CreateScope(); } + + /// + /// Creates a new that can be used to resolve scoped services. + /// + /// The to create the scope from. + /// A that can be used to resolve scoped services. + public static AsyncServiceScope CreateAsyncScope(this IServiceProvider provider) + { + return new AsyncServiceScope(provider.CreateScope()); + } } } From 6c0ba3a257a8edf5aecaecd5593a75aa47e80480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rkstr=C3=B6m?= Date: Mon, 26 Apr 2021 21:09:36 +0300 Subject: [PATCH 2/8] Make AsyncServiceScope readonly Co-authored-by: David Fowler --- .../src/AsyncServiceScope.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs index c44842b46d9be..042bd4f565003 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs @@ -9,7 +9,7 @@ namespace Microsoft.Extensions.DependencyInjection /// /// A implementation that implements . /// - public struct AsyncServiceScope : IServiceScope, IAsyncDisposable + public readonly struct AsyncServiceScope : IServiceScope, IAsyncDisposable { private readonly IServiceScope _serviceScope; From 78a1726332e52f48718a1be08eb8b6230b250baa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rkstr=C3=B6m?= Date: Mon, 26 Apr 2021 21:11:31 +0300 Subject: [PATCH 3/8] Use null-coalescing for null checking and argument exception. Co-authored-by: David Fowler --- .../src/AsyncServiceScope.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs index 042bd4f565003..7786150e5aabd 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs @@ -20,12 +20,7 @@ namespace Microsoft.Extensions.DependencyInjection /// public AsyncServiceScope(IServiceScope serviceScope) { - if (serviceScope is null) - { - throw new ArgumentNullException(nameof(serviceScope)); - } - - _serviceScope = serviceScope; + _serviceScope = serviceScope ?? throw new ArgumentNullException(nameof(serviceScope)); } /// From 28dc589b2f5fc650f76c003843d61f3ede5cb8a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rkstr=C3=B6m?= Date: Mon, 26 Apr 2021 22:25:00 +0300 Subject: [PATCH 4/8] Make AsyncServiceScope readonly in reference source. --- .../Microsoft.Extensions.DependencyInjection.Abstractions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs index 7370f2cc4b6f8..02ba0389eea29 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs @@ -19,7 +19,7 @@ public partial class ActivatorUtilitiesConstructorAttribute : System.Attribute { public ActivatorUtilitiesConstructorAttribute() { } } - public struct AsyncServiceScope : Microsoft.Extensions.DependencyInjection.IServiceScope, System.IAsyncDisposable + public readonly struct AsyncServiceScope : Microsoft.Extensions.DependencyInjection.IServiceScope, System.IAsyncDisposable { public AsyncServiceScope(Microsoft.Extensions.DependencyInjection.IServiceScope serviceScope) { From d42a96fc0e9ec3f867dec176d4cde995c1ef2bc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rkstr=C3=B6m?= Date: Mon, 26 Apr 2021 22:25:48 +0300 Subject: [PATCH 5/8] Adds tests for AsyncServiceScope and CreateAsyncScope extension method. --- .../tests/DI.Tests/AsyncServiceScopeTests.cs | 112 ++++++++++++++++++ .../DI.Tests/ServiceProviderContainerTests.cs | 61 ++++++++++ .../ServiceProviderServiceExtensionsTest.cs | 18 +++ 3 files changed, 191 insertions(+) create mode 100644 src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/AsyncServiceScopeTests.cs diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/AsyncServiceScopeTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/AsyncServiceScopeTests.cs new file mode 100644 index 0000000000000..dde5ebc57bdc5 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/AsyncServiceScopeTests.cs @@ -0,0 +1,112 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.Extensions.DependencyInjection.Tests +{ + public class AsyncServiceScopeTests + { + [Fact] + public void ThrowsIfServiceScopeIsNull() + { + var exception = Assert.Throws(() => new AsyncServiceScope(null)); + Assert.Equal("serviceScope", exception.ParamName); + } + + [Fact] + public void ReturnsServiceProviderFromWrappedScope() + { + var wrappedScope = new FakeSyncServiceScope(); + var asyncScope = new AsyncServiceScope(wrappedScope); + + Assert.Same(wrappedScope.ServiceProvider, asyncScope.ServiceProvider); + } + + [Fact] + public void CallsDisposeOnWrappedSyncScopeOnDispose() + { + var wrappedScope = new FakeSyncServiceScope(); + var asyncScope = new AsyncServiceScope(wrappedScope); + + asyncScope.Dispose(); + + Assert.True(wrappedScope.DisposeCalled); + } + + [Fact] + public async ValueTask CallsDisposeOnWrappedSyncScopeOnDisposeAsync() + { + var wrappedScope = new FakeSyncServiceScope(); + var asyncScope = new AsyncServiceScope(wrappedScope); + + await asyncScope.DisposeAsync(); + + Assert.True(wrappedScope.DisposeCalled); + } + + [Fact] + public void CallsDisposeOnWrappedAsyncScopeOnDispose() + { + var wrappedScope = new FakeAsyncServiceScope(); + var asyncScope = new AsyncServiceScope(wrappedScope); + + asyncScope.Dispose(); + + Assert.True(wrappedScope.DisposeCalled); + Assert.False(wrappedScope.DisposeAsyncCalled); + } + + [Fact] + public async ValueTask CallsDisposeAsyncOnWrappedSyncScopeOnDisposeAsync() + { + var wrappedScope = new FakeAsyncServiceScope(); + var asyncScope = new AsyncServiceScope(wrappedScope); + + await asyncScope.DisposeAsync(); + + Assert.False(wrappedScope.DisposeCalled); + Assert.True(wrappedScope.DisposeAsyncCalled); + } + + public class FakeServiceProvider : IServiceProvider + { + public object? GetService(Type serviceType) => throw new NotImplementedException(); + } + + public class FakeSyncServiceScope : IServiceScope + { + public FakeSyncServiceScope() + { + ServiceProvider = new FakeServiceProvider(); + } + + public IServiceProvider ServiceProvider { get; } + + public bool DisposeCalled { get; private set; } + + public void Dispose() + { + DisposeCalled = true; + } + } + + public class FakeAsyncServiceScope : FakeSyncServiceScope, IAsyncDisposable + { + public FakeAsyncServiceScope() : base() + { + } + + public bool DisposeAsyncCalled { get; private set; } + + public ValueTask DisposeAsync() + { + DisposeAsyncCalled = true; + + return default; + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderContainerTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderContainerTests.cs index 5831a0ef1b0f3..f5af8984c32da 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderContainerTests.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderContainerTests.cs @@ -895,6 +895,67 @@ public void ProviderScopeDisposeThrowsWhenOnlyDisposeAsyncImplemented() exception.Message); } + [Fact] + public async Task ProviderAsyncScopeDisposeAsyncCallsDisposeAsyncOnServices() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddTransient(); + + var serviceProvider = CreateServiceProvider(serviceCollection); + var scope = serviceProvider.CreateAsyncScope(); + var disposable = scope.ServiceProvider.GetService(); + + await (scope as IAsyncDisposable).DisposeAsync(); + + Assert.True(disposable.DisposeAsyncCalled); + } + + [Fact] + public async Task ProviderAsyncScopeDisposeAsyncPrefersDisposeAsyncOnServices() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddTransient(); + + var serviceProvider = CreateServiceProvider(serviceCollection); + var scope = serviceProvider.CreateAsyncScope(); + var disposable = scope.ServiceProvider.GetService(); + + await (scope as IAsyncDisposable).DisposeAsync(); + + Assert.True(disposable.DisposeAsyncCalled); + } + + [Fact] + public void ProviderAsyncScopeDisposePrefersServiceDispose() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddTransient(); + + var serviceProvider = CreateServiceProvider(serviceCollection); + var scope = serviceProvider.CreateScope(); + var disposable = scope.ServiceProvider.GetService(); + + (scope as IDisposable).Dispose(); + + Assert.True(disposable.DisposeCalled); + } + + [Fact] + public void ProviderAsyncScopeDisposeThrowsWhenOnlyDisposeAsyncImplemented() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddTransient(); + + var serviceProvider = CreateServiceProvider(serviceCollection); + var scope = serviceProvider.CreateScope(); + var disposable = scope.ServiceProvider.GetService(); + + var exception = Assert.Throws(() => (scope as IDisposable).Dispose()); + Assert.Equal( + "'Microsoft.Extensions.DependencyInjection.Tests.ServiceProviderContainerTests+AsyncDisposable' type only implements IAsyncDisposable. Use DisposeAsync to dispose the container.", + exception.Message); + } + [Fact] public void SingletonServiceCreatedFromFactoryIsDisposedWhenContainerIsDisposed() { diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderServiceExtensionsTest.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderServiceExtensionsTest.cs index 9bed4bfe5ab80..33b9c25fcdd8b 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderServiceExtensionsTest.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderServiceExtensionsTest.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Xunit; namespace Microsoft.Extensions.DependencyInjection @@ -213,6 +214,23 @@ public void NonGeneric_GetServices_WithBuildServiceProvider_Returns_EmptyList_Wh Assert.IsType>(services); } + [Fact] + public async Task CreateAsyncScope_Returns_AsyncServiceScope_Wrapping_ServiceScope() + { + // Arrange + var serviceCollection = new ServiceCollection(); + serviceCollection.AddScoped(); + var serviceProvider = serviceCollection.BuildServiceProvider(); + + await using var scope = serviceProvider.CreateAsyncScope(); + + // Act + var service = scope.ServiceProvider.GetService(); + + // Assert + Assert.IsType(service); + } + private static IServiceProvider CreateTestServiceProvider(int count) { var serviceCollection = new ServiceCollection(); From c70741fbbb86df25e929e9a5f0fbbc4e19299be6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rkstr=C3=B6m?= Date: Tue, 27 Apr 2021 21:55:29 +0300 Subject: [PATCH 6/8] Merge generated ref source. --- ...crosoft.Extensions.DependencyInjection.Abstractions.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs index 02ba0389eea29..482c51e78384d 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/ref/Microsoft.Extensions.DependencyInjection.Abstractions.cs @@ -19,11 +19,11 @@ public partial class ActivatorUtilitiesConstructorAttribute : System.Attribute { public ActivatorUtilitiesConstructorAttribute() { } } - public readonly struct AsyncServiceScope : Microsoft.Extensions.DependencyInjection.IServiceScope, System.IAsyncDisposable + public readonly partial struct AsyncServiceScope : Microsoft.Extensions.DependencyInjection.IServiceScope, System.IAsyncDisposable, System.IDisposable { - public AsyncServiceScope(Microsoft.Extensions.DependencyInjection.IServiceScope serviceScope) - { - } + private readonly object _dummy; + private readonly int _dummyPrimitive; + public AsyncServiceScope(Microsoft.Extensions.DependencyInjection.IServiceScope serviceScope) { throw null; } public System.IServiceProvider ServiceProvider { get { throw null; } } public void Dispose() { } public System.Threading.Tasks.ValueTask DisposeAsync() { throw null; } From ff0a56f4bfe67d7ce980613f8b29704f7cb2d8c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rkstr=C3=B6m?= Date: Tue, 27 Apr 2021 21:57:37 +0300 Subject: [PATCH 7/8] Document why 'default' is used instead of 'ValueTask.CompletedTask' --- .../src/AsyncServiceScope.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs index 7786150e5aabd..3c0edf88ab7b9 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/AsyncServiceScope.cs @@ -40,6 +40,8 @@ public ValueTask DisposeAsync() return ad.DisposeAsync(); } _serviceScope.Dispose(); + + // ValueTask.CompletedTask is only available in net5.0 and later. return default; } } From 57edbbfd6f9402853d5e768108164339e117943f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Bj=C3=B6rkstr=C3=B6m?= Date: Tue, 27 Apr 2021 22:03:34 +0300 Subject: [PATCH 8/8] Remove unnecessary casts to IDisposable and IAsyncDisposable in tests. --- .../DI.Tests/ServiceProviderContainerTests.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderContainerTests.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderContainerTests.cs index f5af8984c32da..0ca582c004ec2 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderContainerTests.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/tests/DI.Tests/ServiceProviderContainerTests.cs @@ -392,7 +392,7 @@ public async Task AddDisposablesAndAsyncDisposables_DisposeAsync_AllDisposed(boo } await sp.DisposeAsync(); - + Assert.True(disposable.Disposed); Assert.True(asyncDisposable.DisposeAsyncCalled); if (includeDelayedAsyncDisposable) @@ -449,7 +449,7 @@ private class InnerSingleton public InnerSingleton(ManualResetEvent mre1, ManualResetEvent mre2) { // Making sure ctor gets called only once - Assert.True(!mre1.WaitOne(0) && !mre2.WaitOne(0)); + Assert.True(!mre1.WaitOne(0) && !mre2.WaitOne(0)); // Then use mre2 to signal execution reached this ctor call mre2.Set(); @@ -493,13 +493,13 @@ public async Task GetRequiredService_ResolvingSameSingletonInTwoThreads_SameServ // This waits on InnerSingleton singleton lock that is taken in thread 1 innerSingleton = sp.GetRequiredService(); }); - + mreForThread3.WaitOne(); // Set a timeout before unblocking execution of both thread1 and thread2 via mre1: Assert.False(mreForThread1.WaitOne(10)); - // By this time thread 1 has already reached InnerSingleton ctor and is waiting for mre1. + // By this time thread 1 has already reached InnerSingleton ctor and is waiting for mre1. // within the GetRequiredService call, thread 2 should be waiting on a singleton lock for InnerSingleton // (rather than trying to instantiating InnerSingleton twice). mreForThread1.Set(); @@ -546,7 +546,7 @@ public async Task GetRequiredService_UsesSingletonAndLazyLocks_NoDeadlock() sb.Append("3"); mreForThread2.Set(); // Now that thread 1 holds lazy lock, allow thread 2 to continue - // by this time, Thread 2 is holding a singleton lock for Thing2, + // by this time, Thread 2 is holding a singleton lock for Thing2, // and Thread one holds the lazy lock // the call below to resolve Thing0 does not hang // since singletons do not share the same lock upon resolve anymore. @@ -905,7 +905,7 @@ public async Task ProviderAsyncScopeDisposeAsyncCallsDisposeAsyncOnServices() var scope = serviceProvider.CreateAsyncScope(); var disposable = scope.ServiceProvider.GetService(); - await (scope as IAsyncDisposable).DisposeAsync(); + await scope.DisposeAsync(); Assert.True(disposable.DisposeAsyncCalled); } @@ -920,7 +920,7 @@ public async Task ProviderAsyncScopeDisposeAsyncPrefersDisposeAsyncOnServices() var scope = serviceProvider.CreateAsyncScope(); var disposable = scope.ServiceProvider.GetService(); - await (scope as IAsyncDisposable).DisposeAsync(); + await scope.DisposeAsync(); Assert.True(disposable.DisposeAsyncCalled); } @@ -935,7 +935,7 @@ public void ProviderAsyncScopeDisposePrefersServiceDispose() var scope = serviceProvider.CreateScope(); var disposable = scope.ServiceProvider.GetService(); - (scope as IDisposable).Dispose(); + scope.Dispose(); Assert.True(disposable.DisposeCalled); } @@ -950,7 +950,7 @@ public void ProviderAsyncScopeDisposeThrowsWhenOnlyDisposeAsyncImplemented() var scope = serviceProvider.CreateScope(); var disposable = scope.ServiceProvider.GetService(); - var exception = Assert.Throws(() => (scope as IDisposable).Dispose()); + var exception = Assert.Throws(() => scope.Dispose()); Assert.Equal( "'Microsoft.Extensions.DependencyInjection.Tests.ServiceProviderContainerTests+AsyncDisposable' type only implements IAsyncDisposable. Use DisposeAsync to dispose the container.", exception.Message); @@ -1092,7 +1092,7 @@ private async Task ResolveUniqueServicesConcurrently() { var types = new Type[] { - typeof(A), typeof(B), typeof(C), typeof(D), typeof(E), + typeof(A), typeof(B), typeof(C), typeof(D), typeof(E), typeof(F), typeof(G), typeof(H), typeof(I), typeof(J) };