2

我正在用 FluentScheduler 试验 ASP.net Core API 中的一些后台任务。

该作业应根据几个标准在特定时间间隔每天发送推送通知。我已经浏览了文档并实现了一个测试功能以在控制台窗口中打印一些输出。它按预期的时间间隔工作。

但我要做的实际工作涉及数据库上下文,它提供必要的信息来执行发送通知的标准。

我的问题是我无法在MyJob类中使用带参数的构造函数,这会引发缺少方法异常

PS:根据 Scott Hanselman 的这篇文章,FluentScheduler 似乎很有名,但我无法从在线社区获得任何帮助。但显然,它很容易掌握。

public class MyJob : IJob
{
    private ApplicationDbContext _context;

    public MyJob(ApplicationDbContext context)
    {
        _context = context;
    }

    public void Execute()
    {
        Console.WriteLine("Executed");
        SendNotificationAsync();
    }

    private async Task SendNotificationAsync()
    {
        var overdues = _context.Borrow.Join(
            _context.ApplicationUser,
            b => b.ApplicationUserId,
            a => a.Id,
            (a, b) => new { a, b })
            .Where(z => (z.a.ReturnedDate == null) && (z.a.BorrowApproval == 1))
            .Where(z => z.a.ReturnDate.Date == new DateTime().Date.AddDays(1).Date)
            .Select(z => new { z.a.ApplicationUserId, z.a.Book.ShortTitle, z.a.BorrowedDate, z.b.Token })
            .ToList();

        Console.WriteLine("Acknowledged");

        foreach (var r in overdues)
        {
            string message = "You are running late! The book '" + r.ShortTitle + "' borrowed on '" + r.BorrowedDate + "' due tomorrow.";
            Console.WriteLine(message);
            await new PushNotificationService().sendAsync(r.Token, "Due Tomorrow!", message);
        }
    }
}
4

3 回答 3

2

注意- 在文档中它说不要使用 IJobFactory 因为它很快就会被弃用,但它在过去 3.4 个月的生产中为我工作 - https://github.com/fluentscheduler/FluentScheduler/issues/71

我正在使用Windows 控制台应用程序,该应用程序用于Autofac将其作为 Windows 服务运行。Fluent SchedulerTopShelf

要在 FluentScheduler 中使用依赖注入,您必须设置一个作业工厂来解决依赖关系。

所以首先JobFactory通过实施来设置IJobFactory

像这样 -

public class MyJobFactory : IJobFactory
{
    public IJob GetJobInstance<T>() where T : IJob
    {
        return MyContainer.GetJobInstance<T>();
    }
}

现在在作业工厂中,因为我正在使用Autofac我正在设置一个具有 2 种方法的容器

1 - ConfigureDependencies()- 只调用一次来设置容器:

2 - GetJobInstance()- 被调用MyJobFactory 来解析 ta Job 实例

public class MyContainer
{
    public static IContainer Container { get; set; }

    public static void ConfigureDependencies()
    {
        var builder = new ContainerBuilder();

        // Jobs
        builder.RegisterType<MyJob>().As<MyJob>();

        // DB Contexts

        // Others

        Container = builder.Build();
    }


    public static IJob GetJobInstance<T>() where T : IJob
    {
        return Container.Resolve<T>();
    }
}

然后当你启动你的应用程序/服务时,它看起来像这样。

public void Start()
{
    // Configure Dependency Injection
    MyContainer.ConfigureDependencies();

    // Setup the Fluent Scheduler - 
    JobManager.JobFactory = new MyJobFactory();

    JobManager.UseUtcTime();

    JobManager.Initialize(new MyJobRegistry());     
}

然后我通过添加 2 个构造函数创建了一个 Job -

1 - 无参数

2 - 带有注入对象的构造函数

例如

public class MyJob : IJob
{
    public static string JobName = "MyJob";

    private readonly ICompaniesProvider _companiesProvider;

    // parameter-less constructor
    public MyJob() { }

    // injecting HERE
    public MyJob(ICompaniesProvider companiesProvider)
    {
        _companiesProvider = companiesProvider;

    }

    public void Execute()
    {



    }
}

编辑

由于不推荐使用的问题IJobFactory,您可以直接调用容器并获取作业实例,然后再将其添加到 JobManager

public void Start()
{
    // Configure Dependency Injection
    MyContainer.ConfigureDependencies();

    JobManager.UseUtcTime();
    JobManager.Start();

    var myJob = MyContainer.GetJobInstance<MyJob>();

    Action<Schedule> schedule = s => s.ToRunEvery(1).Hours().At(0);

    JobManager.AddJob(myJob, schedule);
}
于 2018-03-29T11:35:22.023 回答
2

从 IJob 的源代码看来,实现 IJob 的类需要有一个无参数的默认构造函数。由于 FluentScheduler 也支持 lambdas,让你的依赖注入库创建你的对象可能更容易,然后Execute像这样调用方法:

var myJob = new MyJob(new ApplicationDbContext());
Schedule(() => myJob.Execute()).ToRunEvery(1).Days().At(21, 15);

或者自己调用构造函数:

// Schedule a job using a factory method and pass parameters to the constructor.
Schedule(() => new MyJob(new ApplicationDbContext())).ToRunNow().AndEvery(2).Seconds();
于 2017-08-09T15:16:14.713 回答
0

我在这里发布了类似的答案-https ://stackoverflow.com/a/51167073/7166609

我使用了 Application 服务范围,注入到注册表的构造函数中,并使用此范围来获取作业类的 execute 方法中的对象。

于 2018-07-04T07:21:38.090 回答