【问题标题】:access context in a hosted service在托管服务中访问上下文
【发布时间】:2019-05-19 11:44:33
【问题描述】:

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

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 吗? 如果您需要更多信息,请告诉我。

【问题讨论】:

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


    【解决方案1】:

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

    上下文是有范围的,这意味着它被设计为具有非常短的生命周期(仅适用于特定的“范围”,例如单个 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")));
    

    【讨论】:

    • 快 5 秒,然后是我 :) 除了我在想ContextUsers
    • 不起作用。它给了我一个错误。 An unhandled exception of type 'System.InvalidOperationException' occurred in System.Private.CoreLib.dll: 'Cannot consume scoped service 'Products.Models.Context' from singleton 'Microsoft.AspNetCore.Hosting.Internal.HostedServiceExecutor'.'
    • 我明白了。我现在明白了这个问题。在这种情况下,您的答案就在这里:stackoverflow.com/a/48368934/1202807
    • 我在回答中添加了一些解释,希望您能更清楚地了解为什么您必须在这里跳过障碍。
    猜你喜欢
    • 2011-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-17
    • 2020-05-14
    • 1970-01-01
    相关资源
    最近更新 更多