首页 > 解决方案 > 将数据库上下文注入 Hangfire Recurring 作业的正确方法是什么?

问题描述

我正在使用 HangFire 定期在后台向用户发送电子邮件。

我正在从数据库中获取电子邮件地址,但我不确定我是否将数据库上下文“注入”到负责正确发送电子邮件的服务中

这工作正常,有没有更好的方法来做到这一点?

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

标签: c#asp.net-core.net-corehangfire

解决方案


我只是查看了类似的问题,并没有在一个地方找到信息,所以在这里发布我的解决方案。

假设您已Context配置为服务,即

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    ....
    services.AddDbContext<Context>(options => { ... });
    ....
}

这使得IServiceProvider能够解决Context依赖关系。

接下来,我们需要更新MessageService类,以免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);

推荐阅读