2

I am experimenting with FluentScheduler for some background tasks in ASP.net Core API.

The job should send push notifications every day at a particular time interval based on few criteria. I had gone through the document and implemented a test functionality to print some output in the console window. It worked as expected with predicted time interval.

But the actual job I am going to do with that involves database context which provides necessary information to perform the criteria to send out the notifications.

My problem is I am unable to use constructor with parameter in MyJob class which is throwing missing method exception

PS: As per this article from Scott Hanselman, FluentScheduler seems to be quite famous but I could not get any help from online communities. But obviously, it's quite easy to grasp.

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

3 Answers 3

2

From the source code for IJob, it looks like your class that implements IJob needs to have a parameterless default constructor. Since FluentScheduler also supports lambdas, it may be easier to have your dependency injection library create your object, then call the Execute method like so:

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

Or call the constructor yourself:

// Schedule a job using a factory method and pass parameters to the constructor.
Schedule(() => new MyJob(new ApplicationDbContext())).ToRunNow().AndEvery(2).Seconds();
Sign up to request clarification or add additional context in comments.

8 Comments

new ApplicationDbContext() Isn't supposed to be instantiated object already from ConfigureServices?
It's just a placeholder for however you are obtaining ApplicationDbContext
new MyJob(new ApplicationDbContext()) isn't accepting. same error as no mssing method error
How are you obtaining an instance of ApplicationDbContext currently?
I am not able to. That is the problem. Somehow I can inject the already running instance of the DbContext into the Schedule I will be able to accomplish my task.
|
2

Note - In the documentation it says not to use IJobFactory because it is going to be deprecated soon, but it is working for me in Production for past 3,4 months - https://github.com/fluentscheduler/FluentScheduler/issues/71

I am using Autofac and Fluent Scheduler in a Windows Console Application which uses TopShelf to run it as a Windows Service.

To use Dependency Injection in FluentScheduler you have to setup a Job Factory to resolve the dependencies.

So first setup a JobFactory by implementing IJobFactory

Like this -

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

Now in the Job Factory because I'm using Autofac I am setting up a Container which has 2 methods

1 - ConfigureDependencies() - Which is only called once to setup the Container:

2 - GetJobInstance() - Which is called by the MyJobFactory to resolve t a Job instance

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

Then when you Start you application/service, it will look something like this.

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

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

    JobManager.UseUtcTime();

    JobManager.Initialize(new MyJobRegistry());     
}

Then I've created a Job by adding 2 constructors -

1 - Parameter-less

2 - The constructor with Injected Objects

e.g.

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()
    {



    }
}

EDIT

Because of deprecated issue of IJobFactory, you could just call the Container Directly and get a Job Instance before adding it to the 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);
}

Comments

0

I have posted the similar answer here- https://stackoverflow.com/a/51167073/7166609

I have used the Application service scope, injected in the registry's constructor and used this scope to get the objects in the execute method of my job class.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.