简体   繁体   中英

.NET Core Scoped called in Singleton through DI

I'm getting an error in 2.0 that I used not to get in .Net Core 1.1.

Cannot consume scoped service 'ArithmosDaily.Data.ArithmosContext' from singleton 'ArithmosDaily.IHangfireJobSchedulerService'.

I am using Hangfire, and I need it to access my database (so I inject my context through DI) to update the database with some data from an API on a schedule. So it appears the DbContext is instantiated as Scoped, and I am setting my Hangfire service as a Singleton. In Core 1.1, there was no check for Scoped nested inside a Singleton. I know this concept works, because I ripped it out of another of my projects in a Core 1.1 project and nesting the Context inside my Singleton service works fine. (Which is annoying me that Microsoft feels the need to control me just because I may do something bad).

So, I change my Hangfire Service from Singleton to Scoped, hoping since my DbContext is apparently Scoped, that Scoped inside Scoped would be fine and instead I get this error: Cannot resolve scoped service 'ArithmosDaily.IHangfireJobSchedulerService' from root provider. I still have no clue what that one even means.

After doing a little bit of digging, I came across the two links at the bottom of my post (and so far that's all I can find). I tried setting services.BuildServiceProvider(false); in my Startup as suggested in the first link, but that didn't change anything in my Configure: I still get the error when setting up my service.

I am totally stumped and not sure what else to try. Maybe I have code in the wrong spot? I'm not sure.

Here is my code for Startup and Configure:

public void ConfigureServices(IServiceCollection services)
{
    services.BuildServiceProvider(false);

    string conn = Configuration.GetConnectionString("Arithmos");
    services.AddDbContext<ArithmosContext>(options => options.UseSqlite(conn));

    services.AddMvc();

    services.AddHangfire(x => x.UseSQLiteStorage(conn));
    services.AddScoped<IHangfireJobSchedulerService, HangfireJobSchedulerService>();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime lifetime)
{
    lifetime.ApplicationStarted.Register(OnStartup);
    lifetime.ApplicationStopping.Register(OnShutdown);

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseBrowserLink();
    }
    else
        app.UseExceptionHandler("/Error");

    app.UseStaticFiles();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller}/{action=Index}/{id?}");
    });

    app.UseHangfireServer();
    app.UseHangfireDashboard(options: new DashboardOptions
    {
        Authorization = new[] { new HangfireAuthorizationFilter() }
    });
    jobSchedulerService = app.ApplicationServices.GetRequiredService<IHangfireJobSchedulerService>();
}

I have come across these questions but they haven't helped me too much:

ASP.Net Core 2 ServiceProviderOptions.ValidateScopes Property

Cannot resolve scoped service Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.IViewBufferScope from root provider

In Core 1.1, there was no check for Scoped nested inside a Singleton.

There was, actually. But it was not enabled by default. This was IMO a mistake in .NET Core 1.

the Context inside my Singleton service works fine.

That such thing works is rather exceptional, and that's why blocking this by default is a good thing. A DbContext, for instance, is not thread-safe and keeping it alive for the duration of the application will in almost all cases lead to concurrency bugs that will only appear when running in production, when multiple requests come in simultaneously.

It this doesn't cause bugs in your situation, it is the exception, not the rule.

Cannot resolve scoped service 'ArithmosDaily.IHangfireJobSchedulerService' from root provider. I still have no clue what that one even means.

That error is indeed very confusing. What this means is that, with the .NET Core container, you should always resolve from an IServiceScope.ServiceProvider (or an injected IServiceProvider), but never from the root IServiceProvider . When running inside an ASP.NET Core request, the framework will automatically call . When running inside an ASP.NET Core request, the framework will automatically call ServiceProviderServiceExtensions.CreateScope` on your behalf and use that scope to resolve controllers and other services for you. When running outside a web request, you might need to create a scope yourself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM