.NET Core类使用Hangfire和依赖注入每15分钟运行一次方法

问题描述

我通过依赖注入获得了DbContext(IApplicationDbContext)和另一个服务(可以进行API调用)。

我需要每15分钟运行一次Hangfire经常性作业,以联系多个API并获取数据,然后将其放入数据库中。我想拥有一个包含该作业方法的类,但是该作业需要访问DbContext和Service。

我的服务已注册为Singleton,我的DbContext已注册为范围服务。

有人可以告诉我如何创建一个包含每15分钟由Hangfire运行的方法的类以及如何启动此作业吗?

我试图用接口IJobContext创建一个名为JobContext的类,并通过JobContext中的构造函数注入DbContext和ApiService,然后通过AddSingleton进行注册,但是它没有用,因为DbContext的生命周期较短(范围)。

我需要什么:

  1. 包含方法/作业的类
  2. 该类通过DI需要DbContext和ApiService
  3. 在启动时运行此类,以便作业在Hangfire中注册并每15分钟执行一次

类似这样的东西:

public class JobContext : IJobContext
{
    public IApplicationDbContext ApplicationDbContext { get; set; }
    public IApiService ApiService { get; set; }

    public JobContext(IApplicationDbContext applicationDbContext,IApiService apiService)
    {
        ApplicationDbContext = applicationDbContext;
        ApiService = apiService;

        InitJobs();
    }

    public void InitJobs()
    {
        RecurringJob.AddOrUpdate(() => Execute(),Cron.Minutely);
    }

    public void Execute()
    {
        // This is my job... Do some Api requests and save to the Db
        Console.WriteLine("123");
    }
}

然后我尝试的是在Startup.cs#ConfigureServices中(但这失​​败了):

services.AddSingleton<IJobContext,JobContext>();

这是我得到的例外:

System.AggregateException: Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: ##.##.##.IJobContext Lifetime: Singleton ImplementationType: ##.##.##.JobContext': Cannot consume scoped service '##.##.##.IApplicationDbContext' from singleton'##.##.##.IJobContext'.)

非常感谢您的帮助!

解决方法

您需要在课程中创建DbContext的新实例。您不希望您的DbContext是单身人士。

只需将一个范围化的服务工厂注入您的班级即可。您可以使用此方法创建新的作用域并实例化作用域服务。

public class JobContext : IJobContext
{
    public IServiceScopeFactory ServiceScopeFactory { get; set; }
    public IApiService ApiService { get; set; }

    public JobContext(IServiceScopeFactory serviceScopeFactory,IApiService apiService)
    {
        ServiceScopeFactory = serviceScopeFactory;
        ApiService = apiService;

        InitJobs();
    }

    public void InitJobs()
    {
        RecurringJob.AddOrUpdate(() => Execute(),Cron.Minutely);
    }

    public void Execute()
    {
        using var scope = ServiceScopeFactory.CreateScope();
        using var dbContext = scope.ServiceProvider.GetService<IApplicationDbContext>();
        
        // use your dbContext
        // This is my job... Do some Api requests and save to the Db
        Console.WriteLine("123");
    }
}