.NET Core Scoped called in Singleton through DI

孤街浪徒 提交于 2021-02-10 12:42:29

问题


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


回答1:


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 rootIServiceProvider. When running inside an ASP.NET Core request, the framework will automatically callServiceProviderServiceExtensions.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.



来源:https://stackoverflow.com/questions/50362622/net-core-scoped-called-in-singleton-through-di

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!