question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Services added with AddHostedService are unable to resolve registrations in ASP.NET Core 3

See original GitHub issue

Description of the bug

Adding a service with AddHostedService<T>() is unable to resolve types registered with Simple Injector in ASP.NET Core 3. The same code worked in 2.2.

Trying to step through the code it appears that services added with AddHostedService() are being started (and subsequently resolved) earlier in Core 3 than in 2.2, causing registrations to not yet have been added. The Startup.Configure() method is not hit at the time the exception is raised.

Moving the registrations to occur at the end of ConfigureServices() doesn’t help, as despite it fixing the missing registrations it is not possible to then call app.UseSimpleInjector() in Configure() as the hosted service being resolved before Configure() is called locks the container:

The container can’t be changed after the first call to GetInstance, GetAllInstances, Verify, and some calls of GetRegistration. Please see https://simpleinjector.org/locked to understand why the container is locked. The following stack trace describes the location where the container was locked:

at SimpleInjector.Container.GetInstance[TService]()
at SimpleInjector.SimpleInjectorGenericHostExtensions.<>c__DisplayClass0_0`1.<AddHostedService>b__0(IServiceProvider _)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host)
at Test.Web.Program.Main(String[] args) in E:\projects\test\src\backend\Test.Web\Program.cs:line 14

Expected behavior

Type of HostedService is resolved.

Actual behavior

Exception:

The container can’t be changed after the first call to GetInstance, GetAllInstances, Verify, and some calls of GetRegistration. Please see https://simpleinjector.org/locked to understand why the container is locked. The following stack trace describes the location where the container was locked:

To Reproduce

Replace the default Startup with the following:

public class HostedService : IHostedService
{
    public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
    public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}

public class Startup
{
    private readonly Container container = new Container();

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();

        services.AddSimpleInjector(this.container, options =>
        {
            options.AddHostedService<HostedService>();
        });
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.ApplicationServices.UseSimpleInjector(this.container);

        app.UseStaticFiles();

        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

Additional context

  • Simple Injector 4.7.1
  • .NET Core 3

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:15

github_iconTop GitHub Comments

5reactions
dotnetjunkiecommented, Sep 30, 2019

btw thank you for this detailed and excellent bug report. This is how I rather see everyone pointing their bugs and questions.

3reactions
dotnetjunkiecommented, Apr 21, 2020

Crêpe! Yet another unfortunate breaking change in ASP.NET Core v3. I will investigate this and report back to you when I found a workaround or have a fix available. Might take a few days for me to get to this point though.

Read more comments on GitHub >

github_iconTop Results From Across the Web

.Net core 3.1 - IHosted service (AddHostedService<T>) is ...
Net core 3.1 - IHosted service (AddHostedService<T>) is not resolving Dependency registrations. We have an API project in.net core and one ...
Read more >
Use scoped services within a BackgroundService - .NET
In this tutorial, you learn how to: Resolve scoped dependencies in a singleton BackgroundService. Delegate work to a scoped service. Implement ...
Read more >
ASP.Net Core API Error (Unable to resolve service for type ' ...
I built a Web API using ASP.Net Core (from Microsoft Tutorial). When calling the API, I got this error below: The error can...
Read more >
ASP.NET Core — Autofac 7.0.0 documentation
This example shows ASP.NET Core 1.1 - 2.2 usage, where you call services.AddAutofac() on the WebHostBuilder . This is not for ASP.NET Core...
Read more >
Hosted service dependency injection. ...
Add service to IServiceCollection NOT in ConfigureServices. ... NET Core Dependency Injection (DI) layer to support SignalR. NET Core native DI container.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found