将数据库上下文注入 Hangfire 重复作业的正确方法是什么?
What is an correct way to inject db context to Hangfire Recurring job?
我使用 HangFire 在后台定期向用户发送电子邮件。
我正在从数据库获取电子邮件地址,但我不确定我是否是 "injecting" 负责正确发送电子邮件的服务的数据库上下文
这个工作正常,有更好的方法吗?
public void Configure(IApplicationBuilder app, IHostingEnvironment env, Context context)
{
(...)
app.UseHangfireDashboard();
app.UseHangfireServer(new BackgroundJobServerOptions
{
HeartbeatInterval = new System.TimeSpan(0, 0, 5),
ServerCheckInterval = new System.TimeSpan(0, 0, 5),
SchedulePollingInterval = new System.TimeSpan(0, 0, 5)
});
RecurringJob.AddOrUpdate(() => new MessageService(context).Send(), Cron.Daily);
(...)
app.UseMvc();
}
public class MessageService
{
private Context ctx;
public MessageService(Context c)
{
ctx = c;
}
public void Send()
{
var emails = ctx.Users.Select(x => x.Email).ToList();
foreach (var email in emails)
{
sendEmail(email, "sample body");
}
}
}
您的问题肯定需要使用 DI(StructureMap 等)。请重构您的配置文件并将 "Context" class 依赖项与配置 class 分离。还引入一个容器 class 来映射 DI classes(自动或手动)。
将容器添加到 Hangfire:
GlobalConfiguration.Configuration.UseStructureMapActivator(Bootstrapper.Bootstrap());
同时更改配置中的作业注册 class:
RecurringJob.AddOrUpdate<MessageService>(x => x.Send(), Cron.Daily);
我只是看了类似的问题,但没有在一个地方找到相关信息,所以在这里发布我的解决方案。
假设您将 Context
配置为服务,即
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
....
services.AddDbContext<Context>(options => { ... });
....
}
这使得 IServiceProvider
能够解析 Context
依赖关系。
接下来,我们需要更新 MessageService
class 以便不永远持有 Context
而是仅实例化它来执行任务。
public class MessageService
{
IServiceProvider _serviceProvider;
public MessageService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public void Send()
{
using (IServiceScope scope = _serviceProvider.CreateScope())
using (Context ctx = scope.ServiceProvider.GetRequiredService<Context>())
{
var emails = ctx.Users.Select(x => x.Email).ToList();
foreach (var email in emails)
{
sendEmail(email, "sample body");
}
}
}
}
最后我们请求 Hangfire 为我们实例化 MessageService
,它也会友好地为我们解决 IServiceProvider
依赖:
RecurringJob.AddOrUpdate<MessageService>(x => x.Send(), Cron.Daily);
我使用 HangFire 在后台定期向用户发送电子邮件。
我正在从数据库获取电子邮件地址,但我不确定我是否是 "injecting" 负责正确发送电子邮件的服务的数据库上下文
这个工作正常,有更好的方法吗?
public void Configure(IApplicationBuilder app, IHostingEnvironment env, Context context)
{
(...)
app.UseHangfireDashboard();
app.UseHangfireServer(new BackgroundJobServerOptions
{
HeartbeatInterval = new System.TimeSpan(0, 0, 5),
ServerCheckInterval = new System.TimeSpan(0, 0, 5),
SchedulePollingInterval = new System.TimeSpan(0, 0, 5)
});
RecurringJob.AddOrUpdate(() => new MessageService(context).Send(), Cron.Daily);
(...)
app.UseMvc();
}
public class MessageService
{
private Context ctx;
public MessageService(Context c)
{
ctx = c;
}
public void Send()
{
var emails = ctx.Users.Select(x => x.Email).ToList();
foreach (var email in emails)
{
sendEmail(email, "sample body");
}
}
}
您的问题肯定需要使用 DI(StructureMap 等)。请重构您的配置文件并将 "Context" class 依赖项与配置 class 分离。还引入一个容器 class 来映射 DI classes(自动或手动)。
将容器添加到 Hangfire:
GlobalConfiguration.Configuration.UseStructureMapActivator(Bootstrapper.Bootstrap());
同时更改配置中的作业注册 class:
RecurringJob.AddOrUpdate<MessageService>(x => x.Send(), Cron.Daily);
我只是看了类似的问题,但没有在一个地方找到相关信息,所以在这里发布我的解决方案。
假设您将 Context
配置为服务,即
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
....
services.AddDbContext<Context>(options => { ... });
....
}
这使得 IServiceProvider
能够解析 Context
依赖关系。
接下来,我们需要更新 MessageService
class 以便不永远持有 Context
而是仅实例化它来执行任务。
public class MessageService
{
IServiceProvider _serviceProvider;
public MessageService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public void Send()
{
using (IServiceScope scope = _serviceProvider.CreateScope())
using (Context ctx = scope.ServiceProvider.GetRequiredService<Context>())
{
var emails = ctx.Users.Select(x => x.Email).ToList();
foreach (var email in emails)
{
sendEmail(email, "sample body");
}
}
}
}
最后我们请求 Hangfire 为我们实例化 MessageService
,它也会友好地为我们解决 IServiceProvider
依赖:
RecurringJob.AddOrUpdate<MessageService>(x => x.Send(), Cron.Daily);