首页 > 解决方案 > 添加使用多个服务的重复作业

问题描述

因此,Hangfire 提供了IRecurringJobManager我们可以用来添加重复作业的功能,但它只支持注入一项服务,当我需要访问多项服务时,我找不到任何示例说明如何执行此操作。

考虑我有两个这样的注册服务:

services.AddTransient<Service1>();
services.AddTransient<Service2>();

我想在我的经常性工作中使用它们。理想情况下,我想做的是:

recurringJobManager.AddOrUpdate<Service1, Service2>("my-job", (service1, service2) =>
{
    // do something
}, Cron.Daily);

但这是不可能的。

这样做的正确方法是什么?我应该注入 IServiceProvider 吗?像这样?

recurringJobManager.AddOrUpdate<IServiceProvider>("my-job", (serviceProvider) =>
{
    var service1 = serviceProvider.GetRequiredService<Service1>();
    var service2 = serviceProvider.GetRequiredService<Service2>();
    // do something
}, Cron.Daily);

那会奏效吗?编辑:不,因为我不能在里面使用语句体

我有点困惑,因为文档没有涵盖这些情况。

标签: c#asp.net-corehangfire

解决方案


一种解决方案似乎是用我需要的服务创建一个单独的类

public class MyJob
{
     private readonly Service1 _service1;
     private readonly Service2 _service2;

     public MyJob(Service1 service1, Service2 service2)
     {
         _service1 = service1;
         _service2 = service2;
     }

     public void DoSomething() {}
}

然后像这样使用它:

recurringJobManager.AddOrUpdate<MyJob>("my-job", myJob => myJob.DoSomething(), Cron.Daily);

注意:我们不能将语句体{}AddOrUpdate. 它始终需要是单个方法调用,因为它需要Expression<T>作为参数。因此,如果我们尝试这样做,recurringJobManager.AddOrUpdate<MyJob>("my-job", myJob => {myJob.DoSomething(); myJob.DoSomething2();}, Cron.Daily);我们将得到编译器错误。

另一种解决方案是将 IServiceProvider 作为参数的单独方法。但我不能保证它有效。

// Or just use MyJob without any parameters if it has access to Service1 and Service2 in case they're members of your class.
private void MyJob(IServiceProvider services)
{
    var service1 = services.GetRequiredService<Service1>();
    var service2 = services.GetRequiredService<Service2>();

    // do something
}

// Add like this or just inject `IServiceProvider` somewhere else e.g. in Configure method
recurringJobManager.AddOrUpdate<IServiceProvider>("my-job", services => MyJob(services), Cron.Daily);

还要检查https://docs.hangfire.io/en/latest/best-practices.html#best-practices

因此,理想情况下,您不应将IServiceProvider其用作工作参数,因为它将被序列化。

⚠️ 重要的事情一开始让我非常困惑!

当你这样做时

var myJob = new MyJob();
RecurringJob.AddOrUpdate("my-job", () => myJob.Run(), Cron.Hourly(0));

它不会使用您创建的那个实例,而是每次都创建一个新实例。所以上面的代码100%等效于

RecurringJob.AddOrUpdate<MyJob>("my-job", (myJob) => myJob.Run(), Cron.Hourly(0));

因为 AddOrUpdate 在内部所做的是解析表达式,确定 myJob 的类型和调用的方法,并构造一个新表达式来创建该类型的实例并在新实例上调用该方法。


推荐阅读