托管服务中的访问上下文

时间:2018-12-19 01:51:05

标签: c# asp.net-core service scope dbcontext

我需要从此类访问上下文,以便可以检查数据库中的某些数据,但是我不知道如何将其传输到以下服务:

internal class TimedHostedService : IHostedService, IDisposable
{
    private readonly ILogger _logger;
    private Timer _timer;



    public TimedHostedService(ILogger<TimedHostedService> logger) //context ?
    {

        _logger = logger; 


    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Timed Background Service is starting.");

        _timer = new Timer(DoWork, null, TimeSpan.Zero,
            TimeSpan.FromSeconds(60));

        return Task.CompletedTask;
    }

    private void DoWork(object state)
    {
        _logger.LogInformation("Atualização automática");


    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Timed Background Service is stopping.");

        _timer?.Change(Timeout.Infinite, 0);

        return Task.CompletedTask;
    }

    public void Dispose()
    {
        _timer?.Dispose();
    }
}

启动文件:

namespace Products
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {

            services.AddCors(o => o.AddPolicy("AllowAllOrigins", builder =>
            {
                builder.AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowAnyOrigin();
            }));

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

            services.AddDbContext<Context>(options =>
                    options.UseSqlServer(Configuration.GetConnectionString("LaprDB")));
            services.AddDbContext<ContextUsers>(options =>
                    options.UseSqlServer(Configuration.GetConnectionString("MyDbConnection")));

            services.AddHostedService<TimedHostedService>();

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }

            app.UseCors("AllowAllOrigins");
            app.UseHttpsRedirection();
            app.UseMvc();

        }
    }
}

我在范围内的工厂中搜索了一些解决方案,但我听不懂。有人可以向我解释如何将上下文传输到TimedHostedService吗? 如果您需要更多信息,请告诉我。

1 个答案:

答案 0 :(得分:2)

托管服务是单例,这意味着在应用程序的生命周期中仅存在该类的一个实例。

上下文是有作用域的,这意味着它的使用寿命很短(仅适用于特定的“范围”,例如单个HTTP请求)。无限期地保持生命状态不好(例如,涉及数据库连接,您无法保证在应用程序的生命周期内保持打开状态)。

如果将Context注入另一个类,则该Context在该类实例的生命周期内将一直存在。对于单例类,这就是应用程序的生命。所以这就是为什么您会得到例外的原因。 .NET Core告诉您:“这不会像您认为的那样工作”

解决方案在这里:https://stackoverflow.com/a/48368934/1202807

简而言之,注入一个IServiceScopeFactory,它使您能够在需要时让DI引擎为您提供作用域类,然后由您决定是否将其保留在附近需要它

private readonly IServiceScopeFactory _scopeFactory;

public TimedHostedService(ILogger<TimedHostedService> logger, IServiceScopeFactory scopeFactory)
{
    _logger = logger; 
    _scopeFactory = scopeFactory;
}

然后您会得到这样的上下文:

using (var scope = scopeFactory.CreateScope())
{
    var context = scope.ServiceProvider.GetRequiredService<Context>();
    //do what you need
}//scope (and context) gets destroyed here

旧答案(这里是错误的,但适用于其他类型的类):

只需将其放入构造函数中,它将被dependency injection注入:

public TimedHostedService(ILogger<TimedHostedService> logger, Context context)
{
    _logger = logger; 
    _context = context;
}

services.AddDbContext()行使它们可用于依赖项注入。既然已经定义了两个,就选择您想要的类型:

services.AddDbContext<Context>(options =>
    options.UseSqlServer(Configuration.GetConnectionString("LaprDB")));
services.AddDbContext<ContextUsers>(options =>
    options.UseSqlServer(Configuration.GetConnectionString("MyDbConnection")));