diff --git a/src/SimpleInjector.Integration.AspNetCore.Mvc.Core/SimpleInjector.Integration.AspNetCore.Mvc.Core.csproj b/src/SimpleInjector.Integration.AspNetCore.Mvc.Core/SimpleInjector.Integration.AspNetCore.Mvc.Core.csproj
index 5f2f8f6..4c1cc27 100644
--- a/src/SimpleInjector.Integration.AspNetCore.Mvc.Core/SimpleInjector.Integration.AspNetCore.Mvc.Core.csproj
+++ b/src/SimpleInjector.Integration.AspNetCore.Mvc.Core/SimpleInjector.Integration.AspNetCore.Mvc.Core.csproj
@@ -3,8 +3,8 @@
Integration library for ASP.NET Core MVC core features for Simple Injector. This includes controller integration.
Simple Injector ASP.NET Core MVC Core Integration
en-US
- 5.1.1
- https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/v5.1.1
+ 5.2.0
+ https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/v5.2.0
5.0.0.0
Simple Injector Contributors
netstandard2.0
@@ -27,8 +27,8 @@
-
-
+
+
diff --git a/src/SimpleInjector.Integration.AspNetCore.Mvc.ViewFeatures/SimpleInjector.Integration.AspNetCore.Mvc.ViewFeatures.csproj b/src/SimpleInjector.Integration.AspNetCore.Mvc.ViewFeatures/SimpleInjector.Integration.AspNetCore.Mvc.ViewFeatures.csproj
index f2b4a7e..be58bd7 100644
--- a/src/SimpleInjector.Integration.AspNetCore.Mvc.ViewFeatures/SimpleInjector.Integration.AspNetCore.Mvc.ViewFeatures.csproj
+++ b/src/SimpleInjector.Integration.AspNetCore.Mvc.ViewFeatures/SimpleInjector.Integration.AspNetCore.Mvc.ViewFeatures.csproj
@@ -3,8 +3,8 @@
Integration library for ASP.NET Core MVC view features for Simple Injector. This includes view component integration.
Simple Injector ASP.NET Core MVC View Features Integration
en-US
- 5.1.1
- https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/v5.1.1
+ 5.2.0
+ https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/v5.2.0
5.0.0.0
Simple Injector Contributors
netstandard2.0
@@ -28,9 +28,9 @@
-
-
-
+
+
+
diff --git a/src/SimpleInjector.Integration.AspNetCore.Mvc/SimpleInjector.Integration.AspNetCore.Mvc.csproj b/src/SimpleInjector.Integration.AspNetCore.Mvc/SimpleInjector.Integration.AspNetCore.Mvc.csproj
index 05eb4c4..4ff1017 100644
--- a/src/SimpleInjector.Integration.AspNetCore.Mvc/SimpleInjector.Integration.AspNetCore.Mvc.csproj
+++ b/src/SimpleInjector.Integration.AspNetCore.Mvc/SimpleInjector.Integration.AspNetCore.Mvc.csproj
@@ -3,8 +3,8 @@
Integration library for ASP.NET Core MVC for Simple Injector. This package adds tag helper and Razor Pages integration on top of the core functionality.
Simple Injector ASP.NET Core MVC Integration
en-US
- 5.1.1
- https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/v5.1.1
+ 5.2.0
+ https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/v5.2.0
5.0.0.0
Simple Injector Contributors
netstandard2.0
@@ -29,9 +29,9 @@
-
-
-
+
+
+
diff --git a/src/SimpleInjector.Integration.AspNetCore/RequestScopingStartupFilter.cs b/src/SimpleInjector.Integration.AspNetCore/RequestScopingStartupFilter.cs
index b490272..6108365 100644
--- a/src/SimpleInjector.Integration.AspNetCore/RequestScopingStartupFilter.cs
+++ b/src/SimpleInjector.Integration.AspNetCore/RequestScopingStartupFilter.cs
@@ -34,12 +34,18 @@ private void ConfigureRequestScoping(IApplicationBuilder builder)
{
builder.Use(async (httpContext, next) =>
{
- await using (var scope = AsyncScopedLifestyle.BeginScope(this.container))
+ Scope scope = AsyncScopedLifestyle.BeginScope(this.container);
+
+ try
{
scope.SetItem(HttpContextKey, httpContext);
await next();
}
+ finally
+ {
+ await scope.DisposeScopeAsync();
+ }
});
}
}
diff --git a/src/SimpleInjector.Integration.AspNetCore/SimpleInjector.Integration.AspNetCore.csproj b/src/SimpleInjector.Integration.AspNetCore/SimpleInjector.Integration.AspNetCore.csproj
index 30d4fda..52c34b9 100644
--- a/src/SimpleInjector.Integration.AspNetCore/SimpleInjector.Integration.AspNetCore.csproj
+++ b/src/SimpleInjector.Integration.AspNetCore/SimpleInjector.Integration.AspNetCore.csproj
@@ -3,8 +3,8 @@
Integration library for ASP.NET Core for Simple Injector.
Simple Injector ASP.NET Core Integration
en-US
- 5.1.1
- https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/v5.1.1
+ 5.2.0
+ https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/v5.2.0
5.0.0.0
Simple Injector Contributors
netstandard2.0
@@ -29,11 +29,10 @@
-
-
-
-
-
+
+
+
+
@@ -44,7 +43,12 @@
-
+
+
+
+
+
+
diff --git a/src/SimpleInjector.Integration.AspNetCore/SimpleInjectorAddOptionsAspNetCoreExtensions.cs b/src/SimpleInjector.Integration.AspNetCore/SimpleInjectorAddOptionsAspNetCoreExtensions.cs
index 38dc2ba..6157c7b 100644
--- a/src/SimpleInjector.Integration.AspNetCore/SimpleInjectorAddOptionsAspNetCoreExtensions.cs
+++ b/src/SimpleInjector.Integration.AspNetCore/SimpleInjectorAddOptionsAspNetCoreExtensions.cs
@@ -75,6 +75,11 @@ public static SimpleInjectorAspNetCoreBuilder AddAspNetCore(
services.UseSimpleInjectorAspNetRequestScoping(container);
+ if (options.DisposeContainerWithServiceProvider)
+ {
+ AddContainerDisposalOnShutdown(options, services);
+ }
+
return new SimpleInjectorAspNetCoreBuilder(options);
}
@@ -107,5 +112,44 @@ private static IServiceProviderAccessor CreateServiceProviderAccessor(
return options.ServiceProviderAccessor;
}
}
+
+ private static void AddContainerDisposalOnShutdown(
+ SimpleInjectorAddOptions options, IServiceCollection services)
+ {
+ // DisposeContainerWithServiceProvider only support synchronous disposal, so we replace this with an
+ // ASP.NET Core-specific implementation that actually supports asynchronous disposal. This can be done
+ // with an IHostedService implementation.
+ services.AddSingleton();
+
+ options.Container.Options.ContainerLocking += (_, __) =>
+ {
+ // If there's no IServiceProvider, the property will throw, which is something we want to do at this
+ // point, not later on, when an unregistered type is resolved.
+ IServiceProvider provider = options.ApplicationServices;
+
+ // In order for the wrapper to get disposed of, it needs to be resolved once.
+ provider.GetRequiredService();
+ };
+
+ // By setting the property to false, we prevent the AddSimpleInjector method from adding its own shutdown
+ // behavior.
+ options.DisposeContainerWithServiceProvider = false;
+ }
+
+ private sealed class ContainerDisposeWrapper : IDisposable
+ {
+ private readonly Container container;
+
+ public ContainerDisposeWrapper(Container container) => this.container = container;
+
+ public void Dispose()
+ {
+ // Since we're running in the context of ASP.NET Core, a call to GetResult() will not result in a dead-
+ // lock. It isn't pretty, but it doesn't hurt either, as this is called just once at shutdown. As a
+ // matter of fact, Microsoft's Microsoft.Extensions.Hosting.Internal.Host class takes the exact same
+ // approach.
+ this.container.DisposeContainerAsync().GetAwaiter().GetResult();
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/SimpleInjector.Integration.GenericHost/SimpleInjector.Integration.GenericHost.csproj b/src/SimpleInjector.Integration.GenericHost/SimpleInjector.Integration.GenericHost.csproj
index 87bfcf6..1dc890d 100644
--- a/src/SimpleInjector.Integration.GenericHost/SimpleInjector.Integration.GenericHost.csproj
+++ b/src/SimpleInjector.Integration.GenericHost/SimpleInjector.Integration.GenericHost.csproj
@@ -1,12 +1,12 @@
-
+
Integrates Simple Injector with applications built upon .NET Generic Host.
Simple Injector Generic Host Integration
en-US
- 5.0.0
- https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/5.0.0
+ 5.2.0
+ https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/v5.2.0
5.0.0.0
Simple Injector Contributors
netstandard2.0
@@ -34,14 +34,17 @@
-
-
+
-
+
+
+
+
+
diff --git a/src/SimpleInjector.Integration.GenericHost/SimpleInjectorGenericHostExtensions.cs b/src/SimpleInjector.Integration.GenericHost/SimpleInjectorGenericHostExtensions.cs
index 987a161..63d7343 100644
--- a/src/SimpleInjector.Integration.GenericHost/SimpleInjectorGenericHostExtensions.cs
+++ b/src/SimpleInjector.Integration.GenericHost/SimpleInjectorGenericHostExtensions.cs
@@ -29,6 +29,8 @@ public static SimpleInjectorAddOptions AddHostedService(
throw new ArgumentNullException(nameof(options));
}
+ var services = options.Services;
+
var registration = Lifestyle.Singleton.CreateRegistration(options.Container);
// Let the built-in configuration system dispose this instance.
@@ -36,7 +38,7 @@ public static SimpleInjectorAddOptions AddHostedService(
options.Container.AddRegistration(registration);
- options.Services.AddSingleton(_ =>
+ services.AddSingleton(_ =>
{
return options.Container.GetInstance();
});
diff --git a/src/SimpleInjector.Integration.ServiceCollection/SimpleInjector.Integration.ServiceCollection.csproj b/src/SimpleInjector.Integration.ServiceCollection/SimpleInjector.Integration.ServiceCollection.csproj
index a8ed1c8..7237c73 100644
--- a/src/SimpleInjector.Integration.ServiceCollection/SimpleInjector.Integration.ServiceCollection.csproj
+++ b/src/SimpleInjector.Integration.ServiceCollection/SimpleInjector.Integration.ServiceCollection.csproj
@@ -1,12 +1,12 @@
-
+
Integrates Simple Injector with applications that require the use of IServiceCollection for registration of framework components.
Simple Injector IServiceCollection Integration
en-US
- 5.0.2
- https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/5.0.0
+ 5.2.0
+ https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/v5.2.0
5.0.0.0
Simple Injector Contributors
netstandard2.0
@@ -32,11 +32,11 @@
-
-
-
-
-
+
+
+
+
+
diff --git a/src/SimpleInjector.Integration.ServiceCollection/SimpleInjectorAddOptions.cs b/src/SimpleInjector.Integration.ServiceCollection/SimpleInjectorAddOptions.cs
index af58402..02d2f72 100644
--- a/src/SimpleInjector.Integration.ServiceCollection/SimpleInjectorAddOptions.cs
+++ b/src/SimpleInjector.Integration.ServiceCollection/SimpleInjectorAddOptions.cs
@@ -68,10 +68,13 @@ public IServiceProviderAccessor ServiceProviderAccessor
public bool AutoCrossWireFrameworkComponents { get; set; } = true;
///
- /// Gets or sets the value indicating whether the instance ued by the
+ /// Gets or sets the value indicating whether the instance used by the
/// application should be disposed when the framework's is disposed.
/// The is typically disposed of on application shutdown, which is also
- /// the time to dispose the Container. The default value is true.
+ /// the time to dispose the Container. The default value is true. Please disable this option in case
+ /// asynchronous disposal is required. If there are Singleton registrations that implement IAsyncDisposable,
+ /// this property should be set to false and the Container should be disposed of manually by calling
+ /// .
///
/// A boolean value.
public bool DisposeContainerWithServiceProvider { get; set; } = true;
@@ -83,7 +86,7 @@ public IServiceProviderAccessor ServiceProviderAccessor
/// is called, or when ASP.NET Core resolves its hosted services (whatever comes first).
///
/// The instance.
- internal IServiceProvider ApplicationServices
+ public IServiceProvider ApplicationServices
{
get
{
diff --git a/src/SimpleInjector.Integration.ServiceCollection/SimpleInjectorServiceCollectionExtensions.cs b/src/SimpleInjector.Integration.ServiceCollection/SimpleInjectorServiceCollectionExtensions.cs
index 8859df4..04bd845 100644
--- a/src/SimpleInjector.Integration.ServiceCollection/SimpleInjectorServiceCollectionExtensions.cs
+++ b/src/SimpleInjector.Integration.ServiceCollection/SimpleInjectorServiceCollectionExtensions.cs
@@ -438,8 +438,6 @@ private static void AddAutoCrossWiring(SimpleInjectorAddOptions options)
private static void AddContainerDisposalOnShutdown(
IServiceCollection services, SimpleInjectorAddOptions options)
{
- services.TryAddSingleton(options.Container);
-
// This wrapper implements disposable and allows the container to be disposed of when
// IServiceProvider is disposed of. Just like Simple Injector, however, MS.DI will only
// dispose of instances that are registered using this overload (not using AddSingleton(T)).
@@ -452,7 +450,8 @@ private static void AddContainerDisposalOnShutdown(
IServiceProvider provider = options.ApplicationServices;
// In order for the wrapper to get disposed of, it needs to be resolved once.
- provider.GetRequiredService();
+ var wrapper = provider.GetRequiredService();
+ wrapper.FrameworkProviderType = provider.GetType();
};
}
@@ -648,15 +647,45 @@ private sealed class NullSimpleInjectorHostedService : IHostedService
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
- private sealed class ContainerDisposeWrapper : IDisposable, IAsyncDisposable
+ private sealed class ContainerDisposeWrapper : IDisposable
{
private readonly Container container;
public ContainerDisposeWrapper(Container container) => this.container = container;
- public void Dispose() => this.container.Dispose();
+ public Type FrameworkProviderType { get; internal set; } = typeof(IServiceProvider);
- public ValueTask DisposeAsync() => this.container.DisposeAsync();
+ public void Dispose()
+ {
+ try
+ {
+ // NOTE: We can't call container.DisposeContainerAsync().GetAwaiter().GetResult(), because we don't
+ // know the context in which this library is running. If it's ASP.NET Core, it would be okay to
+ // call GetResult(), but in case we're running in a UI framework, GetResult() might result in a
+ // deadlock.
+ this.container.Dispose();
+ }
+ catch (InvalidOperationException ex)
+ when (ex.Message.Contains("IAsyncDisposable") && ex.Message.Contains("IDisposable"))
+ {
+ // When we get here, Dispose complained that there was a Singleton registration that implements
+ // IAsyncDisposable, while this is a synchronous Dispose call.
+ throw new InvalidOperationException(
+ $"Simple Injector was configured to be disposed of together with the application's " +
+ $"{this.FrameworkProviderType.ToFriendlyName()}. This configuration is not suited for " +
+ $"asynchronous disposal. The Simple Injector Container, however, contains a Singleton that " +
+ $"implements IAsyncDisposable, which cannot be disposed of synchronously. To fix this " +
+ $"problem, configure Simple Injector by setting {nameof(SimpleInjectorAddOptions)}." +
+ $"{nameof(SimpleInjectorAddOptions.DisposeContainerWithServiceProvider)} to false and " +
+ $"manually call 'await Container.{nameof(Container.DisposeContainerAsync)}()' at " +
+ $"application shutdown. e.g.:\n" +
+ $"services.{nameof(SimpleInjectorServiceCollectionExtensions.AddSimpleInjector)}(container, " +
+ $"options => {{ " +
+ $"options.{nameof(SimpleInjectorAddOptions.DisposeContainerWithServiceProvider)} = false;" +
+ $" }}). {ex.Message}",
+ ex);
+ }
+ }
}
}
}
\ No newline at end of file