diff --git a/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs b/src/Splat.Microsoft.Extensions.DependencyInjection/MicrosoftDependencyResolver.cs index 5e0533bf2..af734a3a7 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(); @@ -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,8 +99,15 @@ public void UpdateContainer(IServiceProvider serviceProvider) 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); + } + _serviceProvider = serviceProvider; + _serviceCollection = null; _isImmutable = true; } } @@ -144,6 +183,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 +218,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 +244,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 +262,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 +292,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 +315,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 } } }