Skip to content
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

WIP fix: dispose IServiceProvider in MicrosoftDependencyResolver #1170

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
/// Microsoft DI implementation for <see cref="IDependencyResolver"/>.
/// </summary>
/// <seealso cref="IDependencyResolver" />
public class MicrosoftDependencyResolver : IDependencyResolver
public class MicrosoftDependencyResolver : IDependencyResolver, IAsyncDisposable
{
private const string ImmutableExceptionMessage = "This container has already been built and cannot be modified.";
private readonly object _syncLock = new();
Expand Down Expand Up @@ -50,6 +50,38 @@
}
}

/// <summary>
/// Updates this instance with a collection of configured services.
/// </summary>
/// <param name="services">An instance of <see cref="IServiceCollection"/>.</param>
public void UpdateContainer(IServiceCollection services)
{
#if NETSTANDARD || NETFRAMEWORK
if (services is null)
{
throw new ArgumentNullException(nameof(services));
}
#else
ArgumentNullException.ThrowIfNull(services);

Check warning on line 65 in src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs

View check run for this annotation

Codecov / codecov/patch

src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs#L65

Added line #L65 was not covered by tests
#endif

if (_isImmutable)
{
throw new InvalidOperationException(ImmutableExceptionMessage);

Check warning on line 70 in src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs

View check run for this annotation

Codecov / codecov/patch

src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs#L70

Added line #L70 was not covered by tests
}

lock (_syncLock)

Check warning on line 73 in src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs

View check run for this annotation

Codecov / codecov/patch

src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs#L73

Added line #L73 was not covered by tests
{
if (_serviceProvider is not null)
{
DisposeServiceProvider(_serviceProvider);
_serviceProvider = null;

Check warning on line 78 in src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs

View check run for this annotation

Codecov / codecov/patch

src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs#L77-L78

Added lines #L77 - L78 were not covered by tests
}

_serviceCollection = services;
}
}

Check warning on line 83 in src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs

View check run for this annotation

Codecov / codecov/patch

src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs#L81-L83

Added lines #L81 - L83 were not covered by tests

/// <summary>
/// Updates this instance with a configured service Provider.
/// </summary>
Expand All @@ -67,8 +99,15 @@

lock (_syncLock)
{
_serviceCollection = null;
// can be null if constructor using IServiceCollection was used.
// and no fetch of a service was called.
if (_serviceProvider is not null)
{
DisposeServiceProvider(_serviceProvider);

Check warning on line 106 in src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs

View check run for this annotation

Codecov / codecov/patch

src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs#L106

Added line #L106 was not covered by tests
}

_serviceProvider = serviceProvider;
_serviceCollection = null;
_isImmutable = true;
}
}
Expand Down Expand Up @@ -144,6 +183,7 @@
}

// required so that it gets rebuilt if not injected externally.
DisposeServiceProvider(_serviceProvider);
_serviceProvider = null;
}
}
Expand Down Expand Up @@ -178,6 +218,7 @@
}

// required so that it gets rebuilt if not injected externally.
DisposeServiceProvider(_serviceProvider);
_serviceProvider = null;
}
}
Expand All @@ -203,6 +244,7 @@
if (_serviceCollection is null)
{
// required so that it gets rebuilt if not injected externally.
DisposeServiceProvider(_serviceProvider);

Check warning on line 247 in src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs

View check run for this annotation

Codecov / codecov/patch

src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs#L247

Added line #L247 was not covered by tests
_serviceProvider = null;
return;
}
Expand All @@ -220,6 +262,7 @@
}

// required so that it gets rebuilt if not injected externally.
DisposeServiceProvider(_serviceProvider);
_serviceProvider = null;
}
}
Expand Down Expand Up @@ -249,6 +292,16 @@
&& keyedServiceProvider.GetKeyedService(serviceType, contract) is not null;
}

/// <inheritdoc/>
public async ValueTask DisposeAsync()
{
if (_serviceProvider is IAsyncDisposable d)
{
await d.DisposeAsync();
GC.SuppressFinalize(this);

Check warning on line 301 in src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs

View check run for this annotation

Codecov / codecov/patch

src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs#L300-L301

Added lines #L300 - L301 were not covered by tests
}
}

Check warning on line 303 in src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs

View check run for this annotation

Codecov / codecov/patch

src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs#L303

Added line #L303 was not covered by tests

/// <inheritdoc />
public void Dispose()
{
Expand All @@ -262,6 +315,18 @@
/// <param name="disposing">Whether or not the instance is disposing.</param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
DisposeServiceProvider(_serviceProvider);

Check warning on line 320 in src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs

View check run for this annotation

Codecov / codecov/patch

src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs#L320

Added line #L320 was not covered by tests
}
}

Check warning on line 322 in src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs

View check run for this annotation

Codecov / codecov/patch

src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs#L322

Added line #L322 was not covered by tests

private static void DisposeServiceProvider(IServiceProvider? sp)
{
if (sp is IDisposable d)
{
d.Dispose();
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ public static class SplatMicrosoftExtensions
/// </summary>
/// <param name="serviceCollection">The <see cref="IServiceCollection"/>.</param>
public static void UseMicrosoftDependencyResolver(this IServiceCollection serviceCollection) =>
#pragma warning disable CA2000
// Will be disposed with the InternalLocator
Locator.SetLocator(new MicrosoftDependencyResolver(serviceCollection));
#pragma warning restore CA2000

/// <summary>
/// Initializes an instance of <see cref="MicrosoftDependencyResolver"/> that overrides the default <see cref="Locator"/>
Expand All @@ -37,7 +40,10 @@ public static void UseMicrosoftDependencyResolver(this IServiceProvider serviceP
}
else
{
#pragma warning disable CA2000
// Will be disposed with the InternalLocator
Locator.SetLocator(new MicrosoftDependencyResolver(serviceProvider));
#pragma warning restore CA2000
}
}
}
Loading