在托管服务中访问上下文
access context in a hosted service
我需要从此 class 访问上下文,以便我可以检查数据库中的一些数据,但我不知道如何将其传输到以下服务:
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 吗?
如果您需要更多信息,请告诉我。
托管服务是一个单例,这意味着在应用程序的生命周期中只有一个 class 实例存在。
上下文是有范围的,这意味着它被设计为具有非常短的生命周期(仅针对特定 "scope",如单个 HTTP 请求)。它不擅长无限期地保持活动状态(涉及数据库连接,例如,您不能保证它会在应用程序的生命周期内保持打开状态)。
如果您将一个 Context 注入另一个 class,则该 Context 将在 class 实例的整个生命周期内存在。对于单例 class,这就是应用程序的生命周期。所以这就是为什么你得到你做的例外。 .NET Core 告诉你:"This isn't going to work the way you think it's going to work"
解决方法在这里:
简而言之,注入一个 IServiceScopeFactory
,它使您能够在需要时要求 DI 引擎为您提供范围 class,然后由您来决定是否保留它 只要你需要就可以.
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
旧答案(这里是错误的,但适用于其他类型的 classes):
只需将它放入您的构造函数中,它就会被 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")));
我需要从此 class 访问上下文,以便我可以检查数据库中的一些数据,但我不知道如何将其传输到以下服务:
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 吗? 如果您需要更多信息,请告诉我。
托管服务是一个单例,这意味着在应用程序的生命周期中只有一个 class 实例存在。
上下文是有范围的,这意味着它被设计为具有非常短的生命周期(仅针对特定 "scope",如单个 HTTP 请求)。它不擅长无限期地保持活动状态(涉及数据库连接,例如,您不能保证它会在应用程序的生命周期内保持打开状态)。
如果您将一个 Context 注入另一个 class,则该 Context 将在 class 实例的整个生命周期内存在。对于单例 class,这就是应用程序的生命周期。所以这就是为什么你得到你做的例外。 .NET Core 告诉你:"This isn't going to work the way you think it's going to work"
解决方法在这里:
简而言之,注入一个 IServiceScopeFactory
,它使您能够在需要时要求 DI 引擎为您提供范围 class,然后由您来决定是否保留它 只要你需要就可以.
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
旧答案(这里是错误的,但适用于其他类型的 classes):
只需将它放入您的构造函数中,它就会被 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")));