контекст доступа в размещенном сервисе - PullRequest
0 голосов
/ 19 декабря 2018

Мне нужен доступ к контексту из этого класса, чтобы я мог проверить некоторые данные из базы данных, но я не знаю, как передать их в службу ниже:

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 голосов
/ 19 декабря 2018

Хостинг-сервис - это одноэлементный, что означает, что для жизни приложения существует только один экземпляр этого класса.

Контекст ограничен, то есть имеет очень короткий срок службы (только дляконкретная «область действия», например один HTTP-запрос).Неполно оставаться в живых бесконечно (например, задействованы соединения БД, которые, как вы можете гарантировать, не будут оставаться открытыми на протяжении всего жизненного цикла приложения).

Если вы вставляете контекст в другой класс,Контекст будет существовать всю жизнь экземпляра этого класса.Для одноэлементного класса это жизнь приложения.Вот почему вы получаете исключение, которое вы делаете..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

Старый ответ (который здесь неправильный, но относится к другим типам классов):

Просто поместите его в конструктор, и он будет вставлен внедрением зависимостей :

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")));
...