From d7d696964cbc4d7d5d00a317bb52a851aa76c3c6 Mon Sep 17 00:00:00 2001 From: Caleb Kiage <747955+calebkiage@users.noreply.github.com> Date: Wed, 31 Jul 2024 15:23:52 +0300 Subject: [PATCH 1/3] fix: dispose IServiceProvider in MicrosoftDependencyResolver --- .../MicrosoftDependencyResolver.cs | 29 ++++++++++++++++++- .../SplatMicrosoftExtensions.cs | 6 ++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs b/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs index bb5ad06c9..e36728d18 100644 --- a/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs +++ b/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs @@ -12,7 +12,7 @@ namespace Splat.Microsoft.Extensions.DependencyInjection; /// Microsoft DI implementation for . /// /// -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(); @@ -68,6 +68,7 @@ public void UpdateContainer(IServiceProvider serviceProvider) lock (_syncLock) { _serviceCollection = null; + DisposeServiceProvider(_serviceProvider); _serviceProvider = serviceProvider; _isImmutable = true; } @@ -144,6 +145,7 @@ public virtual void Register(Func factory, Type? serviceType, string? c } // required so that it gets rebuilt if not injected externally. + DisposeServiceProvider(_serviceProvider); _serviceProvider = null; } } @@ -178,6 +180,7 @@ public virtual void UnregisterCurrent(Type? serviceType, string? contract = null } // required so that it gets rebuilt if not injected externally. + DisposeServiceProvider(_serviceProvider); _serviceProvider = null; } } @@ -203,6 +206,7 @@ public virtual void UnregisterAll(Type? serviceType, string? contract = null) if (_serviceCollection is null) { // required so that it gets rebuilt if not injected externally. + DisposeServiceProvider(_serviceProvider); _serviceProvider = null; return; } @@ -220,6 +224,7 @@ public virtual void UnregisterAll(Type? serviceType, string? contract = null) } // required so that it gets rebuilt if not injected externally. + DisposeServiceProvider(_serviceProvider); _serviceProvider = null; } } @@ -249,6 +254,16 @@ public virtual bool HasRegistration(Type? serviceType, string? contract = null) && keyedServiceProvider.GetKeyedService(serviceType, contract) is not null; } + /// + public async ValueTask DisposeAsync() + { + if (_serviceProvider is IAsyncDisposable d) + { + await d.DisposeAsync(); + GC.SuppressFinalize(this); + } + } + /// public void Dispose() { @@ -262,6 +277,18 @@ public void Dispose() /// Whether or not the instance is disposing. protected virtual void Dispose(bool disposing) { + if (disposing) + { + DisposeServiceProvider(_serviceProvider); + } + } + + private static void DisposeServiceProvider(IServiceProvider? sp) + { + if (sp is IDisposable d) + { + d.Dispose(); + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/Splat.Microsoft.Extensions.DependencyInjection/SplatMicrosoftExtensions.cs b/src/Splat.Microsoft.Extensions.DependencyInjection/SplatMicrosoftExtensions.cs index 65bedea06..a0cc39d13 100644 --- a/src/Splat.Microsoft.Extensions.DependencyInjection/SplatMicrosoftExtensions.cs +++ b/src/Splat.Microsoft.Extensions.DependencyInjection/SplatMicrosoftExtensions.cs @@ -17,7 +17,10 @@ public static class SplatMicrosoftExtensions /// /// The . 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 /// /// Initializes an instance of that overrides the default @@ -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 } } } From 27fbd27352024453f749c0dbd9960e1d1b8eb128 Mon Sep 17 00:00:00 2001 From: David Vreony Date: Mon, 14 Oct 2024 17:43:51 +0100 Subject: [PATCH 2/3] plug gap for update container for servicecollection --- .../MicrosoftDependencyResolver.cs | 42 ++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs b/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs index e36728d18..3ddad2b83 100644 --- a/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs +++ b/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs @@ -50,6 +50,38 @@ protected virtual IServiceProvider? ServiceProvider } } + /// + /// Updates this instance with a collection of configured services. + /// + /// An instance of . + public void UpdateContainer(IServiceCollection services) + { +#if NETSTANDARD || NETFRAMEWORK + if (services is null) + { + throw new ArgumentNullException(nameof(services)); + } +#else + ArgumentNullException.ThrowIfNull(services); +#endif + + if (_isImmutable) + { + throw new InvalidOperationException(ImmutableExceptionMessage); + } + + lock (_syncLock) + { + if (_serviceProvider is not null) + { + DisposeServiceProvider(_serviceProvider); + _serviceProvider = null; + } + + _serviceCollection = services; + } + } + /// /// Updates this instance with a configured service Provider. /// @@ -67,9 +99,15 @@ public void UpdateContainer(IServiceProvider serviceProvider) lock (_syncLock) { + // can be null if constructor using IServiceCollection was used. + // and no fetch of a service was called. + if (_serviceProvider is not null) + { + DisposeServiceProvider(_serviceProvider); + _serviceProvider = serviceProvider; + } + _serviceCollection = null; - DisposeServiceProvider(_serviceProvider); - _serviceProvider = serviceProvider; _isImmutable = true; } } From 5930e17d75c767919f3b25d046d1b659f3de395e Mon Sep 17 00:00:00 2001 From: David Vreony Date: Mon, 14 Oct 2024 18:54:22 +0100 Subject: [PATCH 3/3] fix re-reg issue --- .../MicrosoftDependencyResolver.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs b/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs index 3ddad2b83..0dff3d6a3 100644 --- a/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs +++ b/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs @@ -104,9 +104,9 @@ public void UpdateContainer(IServiceProvider serviceProvider) if (_serviceProvider is not null) { DisposeServiceProvider(_serviceProvider); - _serviceProvider = serviceProvider; } + _serviceProvider = serviceProvider; _serviceCollection = null; _isImmutable = true; }