Skip to content

Commit

Permalink
Upgraded to Simple Injector v5.2. Fixes #7
Browse files Browse the repository at this point in the history
  • Loading branch information
dotnetjunkie committed Dec 11, 2020
1 parent 21b2ce2 commit 61200f3
Show file tree
Hide file tree
Showing 11 changed files with 138 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<Description>Integration library for ASP.NET Core MVC core features for Simple Injector. This includes controller integration.</Description>
<AssemblyTitle>Simple Injector ASP.NET Core MVC Core Integration</AssemblyTitle>
<NeutralLanguage>en-US</NeutralLanguage>
<VersionPrefix>5.1.1</VersionPrefix>
<PackageReleaseNotes>https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/v5.1.1</PackageReleaseNotes>
<VersionPrefix>5.2.0</VersionPrefix>
<PackageReleaseNotes>https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/v5.2.0</PackageReleaseNotes>
<AssemblyVersion>5.0.0.0</AssemblyVersion>
<Authors>Simple Injector Contributors</Authors>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
Expand All @@ -27,8 +27,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.0.0" />
<PackageReference Include="SimpleInjector" Version="5.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.1.0" />
<PackageReference Include="SimpleInjector" Version="5.2.0" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net451' ">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<Description>Integration library for ASP.NET Core MVC view features for Simple Injector. This includes view component integration.</Description>
<AssemblyTitle>Simple Injector ASP.NET Core MVC View Features Integration</AssemblyTitle>
<NeutralLanguage>en-US</NeutralLanguage>
<VersionPrefix>5.1.1</VersionPrefix>
<PackageReleaseNotes>https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/v5.1.1</PackageReleaseNotes>
<VersionPrefix>5.2.0</VersionPrefix>
<PackageReleaseNotes>https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/v5.2.0</PackageReleaseNotes>
<AssemblyVersion>5.0.0.0</AssemblyVersion>
<Authors>Simple Injector Contributors</Authors>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
Expand All @@ -28,9 +28,9 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.ViewFeatures" Version="2.0.0" />
<PackageReference Include="SimpleInjector" Version="5.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.ViewFeatures" Version="2.1.0" />
<PackageReference Include="SimpleInjector" Version="5.2.0" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net451' ">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<Description>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.</Description>
<AssemblyTitle>Simple Injector ASP.NET Core MVC Integration</AssemblyTitle>
<NeutralLanguage>en-US</NeutralLanguage>
<VersionPrefix>5.1.1</VersionPrefix>
<PackageReleaseNotes>https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/v5.1.1</PackageReleaseNotes>
<VersionPrefix>5.2.0</VersionPrefix>
<PackageReleaseNotes>https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/v5.2.0</PackageReleaseNotes>
<AssemblyVersion>5.0.0.0</AssemblyVersion>
<Authors>Simple Injector Contributors</Authors>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
Expand All @@ -29,9 +29,9 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.RazorPages" Version="2.0.0" />
<PackageReference Include="SimpleInjector" Version="5.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.RazorPages" Version="2.1.0" />
<PackageReference Include="SimpleInjector" Version="5.2.0" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net451' ">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<Description>Integration library for ASP.NET Core for Simple Injector.</Description>
<AssemblyTitle>Simple Injector ASP.NET Core Integration</AssemblyTitle>
<NeutralLanguage>en-US</NeutralLanguage>
<VersionPrefix>5.1.1</VersionPrefix>
<PackageReleaseNotes>https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/v5.1.1</PackageReleaseNotes>
<VersionPrefix>5.2.0</VersionPrefix>
<PackageReleaseNotes>https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/v5.2.0</PackageReleaseNotes>
<AssemblyVersion>5.0.0.0</AssemblyVersion>
<Authors>Simple Injector Contributors</Authors>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
Expand All @@ -29,11 +29,10 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.0.0" />
<PackageReference Include="SimpleInjector" Version="5.1.0" />
<PackageReference Include="SimpleInjector.Integration.ServiceCollection" Version="5.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.1.0" />
<PackageReference Include="SimpleInjector" Version="5.2.0" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net451' ">
Expand All @@ -44,7 +43,12 @@
<ItemGroup>
<None Include="..\Graphics\simpleinjector.png" Pack="true" PackagePath="" />
</ItemGroup>


<ItemGroup>
<ProjectReference Include="..\SimpleInjector.Integration.ServiceCollection\SimpleInjector.Integration.ServiceCollection.csproj" />
<ProjectReference Include="..\SimpleInjector.Integration.GenericHost\SimpleInjector.Integration.GenericHost.csproj" />
</ItemGroup>

<Target Name="PostcompileScript" AfterTargets="Build" Condition=" '$(IsCrossTargetingBuild)' != 'true' ">
<Exec Command="dotnet pack --no-build --configuration $(Configuration)" />
</Target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ public static SimpleInjectorAspNetCoreBuilder AddAspNetCore(

services.UseSimpleInjectorAspNetRequestScoping(container);

if (options.DisposeContainerWithServiceProvider)
{
AddContainerDisposalOnShutdown(options, services);
}

return new SimpleInjectorAspNetCoreBuilder(options);
}

Expand Down Expand Up @@ -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<ContainerDisposeWrapper>();

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<ContainerDisposeWrapper>();
};

// 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();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>
Integrates Simple Injector with applications built upon .NET Generic Host.
</Description>
<AssemblyTitle>Simple Injector Generic Host Integration</AssemblyTitle>
<NeutralLanguage>en-US</NeutralLanguage>
<VersionPrefix>5.0.0</VersionPrefix>
<PackageReleaseNotes>https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/5.0.0</PackageReleaseNotes>
<VersionPrefix>5.2.0</VersionPrefix>
<PackageReleaseNotes>https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/v5.2.0</PackageReleaseNotes>
<AssemblyVersion>5.0.0.0</AssemblyVersion>
<Authors>Simple Injector Contributors</Authors>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
Expand Down Expand Up @@ -34,14 +34,17 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.1.0" />
<PackageReference Include="SimpleInjector" Version="5.0.0" />
<PackageReference Include="SimpleInjector.Integration.ServiceCollection" Version="5.0.0" />
<PackageReference Include="SimpleInjector" Version="5.2.0" />
</ItemGroup>

<ItemGroup>
<None Include="..\Graphics\simpleinjector.png" Pack="true" PackagePath="" />
</ItemGroup>


<ItemGroup>
<ProjectReference Include="..\SimpleInjector.Integration.ServiceCollection\SimpleInjector.Integration.ServiceCollection.csproj" />
</ItemGroup>

<Target Name="PostcompileScript" AfterTargets="Build" Condition=" '$(IsCrossTargetingBuild)' != 'true' ">
<Exec Command="dotnet pack --no-build --configuration $(Configuration)" />
</Target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,16 @@ public static SimpleInjectorAddOptions AddHostedService<THostedService>(
throw new ArgumentNullException(nameof(options));
}

var services = options.Services;

var registration = Lifestyle.Singleton.CreateRegistration<THostedService>(options.Container);

// Let the built-in configuration system dispose this instance.
registration.SuppressDisposal = true;

options.Container.AddRegistration<THostedService>(registration);

options.Services.AddSingleton<IHostedService>(_ =>
services.AddSingleton<IHostedService>(_ =>
{
return options.Container.GetInstance<THostedService>();
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>
Integrates Simple Injector with applications that require the use of IServiceCollection for registration of framework components.
</Description>
<AssemblyTitle>Simple Injector IServiceCollection Integration</AssemblyTitle>
<NeutralLanguage>en-US</NeutralLanguage>
<VersionPrefix>5.0.2</VersionPrefix>
<PackageReleaseNotes>https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/5.0.0</PackageReleaseNotes>
<VersionPrefix>5.2.0</VersionPrefix>
<PackageReleaseNotes>https://github.com/simpleinjector/SimpleInjector.Integration.AspNetCore/releases/tag/v5.2.0</PackageReleaseNotes>
<AssemblyVersion>5.0.0.0</AssemblyVersion>
<Authors>Simple Injector Contributors</Authors>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
Expand All @@ -32,11 +32,11 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.0.0" />
<PackageReference Include="SimpleInjector" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="2.1.0" />
<PackageReference Include="SimpleInjector" Version="5.2.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,13 @@ public IServiceProviderAccessor ServiceProviderAccessor
public bool AutoCrossWireFrameworkComponents { get; set; } = true;

/// <summary>
/// Gets or sets the value indicating whether the <see cref="Container"/> instance ued by the
/// Gets or sets the value indicating whether the <see cref="Container"/> instance used by the
/// application should be disposed when the framework's <see cref="IServiceProvider"/> is disposed.
/// The <see cref="IServiceProvider"/> is typically disposed of on application shutdown, which is also
/// the time to dispose the Container. The default value is <b>true</b>.
/// the time to dispose the Container. The default value is <b>true</b>. 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
/// <see cref="Container.DisposeContainerAsync"/>.
/// </summary>
/// <value>A boolean value.</value>
public bool DisposeContainerWithServiceProvider { get; set; } = true;
Expand All @@ -83,7 +86,7 @@ public IServiceProviderAccessor ServiceProviderAccessor
/// is called, or when ASP.NET Core resolves its hosted services (whatever comes first).
/// </summary>
/// <value>The <see cref="IServiceProvider"/> instance.</value>
internal IServiceProvider ApplicationServices
public IServiceProvider ApplicationServices
{
get
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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>(T)).
Expand All @@ -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<ContainerDisposeWrapper>();
var wrapper = provider.GetRequiredService<ContainerDisposeWrapper>();
wrapper.FrameworkProviderType = provider.GetType();
};
}

Expand Down Expand Up @@ -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);
}
}
}
}
}

0 comments on commit 61200f3

Please sign in to comment.