Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using FluentScheduler - ASP.NET Core MVC

I currently have a simple website setup with ASP.NET Core MVC (.NET 4.6.1), and I would like to periodically do some processes like automatically send emails at the end of every day to the registered members.

After doing some searching, I came across two common solutions - Quartz.NET and FluentScheduler.

Based on this SO thread, I found the approach of using FluentScheduler more easier to digest and use for my simple task. After quickly implementing the following lines of code into my Program.cs class, I had the emails going out successfully every minute (for testing purposes).

public class Program
{
    public static void Main(string[] args)
    {
        var host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            .UseStartup<Startup>()
            .Build();

            var registry = new Registry();
            JobManager.Initialize(registry);

            JobManager.AddJob(() => MyEmailService.SendEmail(), s => s
                  .ToRunEvery(1)
                  .Minutes());

            host.Run();

    }
}

However, now apart from sending emails I also need to do some back-end processing for e.g. updating the user records in the DB when mails are being sent out. For this, I normally inject my Entity Framework Context into the constructor of my controllers and use it to get/update SQL records.

My question is, since I cannot really inject these services into the main method, where would be the appropriate place to initialize the registry and add jobs for scheduling?

Thanks for the help, I am a little new to this so a little guidance would be much appreciated!

like image 506
terry96 Avatar asked May 30 '17 11:05

terry96


2 Answers

Instead of Program's Main function, I initialized the same in Startup.cs before app.UseMvc..

public void Configure(...., IDependencyObject dependencyObject)
{
           ....
           JobManager.Initialize(new MyRegistry(dependencyObject));

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "api/{controller}/{action}/{id?}");
            });
}

My registry class looks like this:

public class MyRegistry: Registry
{
    public MyRegistry(IDependencyObject dependencyObject)
    {            
        Schedule(() => new SyncUpJob(dependencyObject)).ToRunNow().AndEvery(10).Seconds();
    }
}

My Job class looks like this:

public class SyncUpJob: IJob
{
    public SyncUpJob(IDependencyObject dependencyObject)
    {
        DependencyObject= dependencyObject;
    }

    public IDependencyObject DependencyObject{ get; set; }

    public void Execute()
    {
        // call the method to run weekly here
    }
}
like image 163
Gaurav Jalan Avatar answered Nov 07 '22 03:11

Gaurav Jalan


You can define all your jobs and their schedules, by subclassing from FluentScheduler Registry class. something like:

public class JobRegistry : Registry {

    public JobRegistry() {
        Schedule<EmailJob>().ToRunEvery(1).Days();
        Schedule<SomeOtherJob>().ToRunEvery(1).Seconds();
    }

}

public class EmailJob : IJob {

    public DbContext Context { get; } // we need this dependency, right?!

    public EmailJob(DbContext context) //constructor injection
    {
        Context = context;
    }

    public void Execute()
    {
        //Job implementation code: send emails to users and update database
    }
}

For injecting dependencies into jobs, you need to implement FluentScheduler IJobFactory interface. GetJobIntance method is called by FluentScheduler for creating job instances. Here you can use any DI library you want; In this sample implementation, I'm going to assume that you use Ninject:

public class MyNinjectModule : NinjectModule {
    public override void Load()
    {
        Bind<DbContext>().To<MyDbContextImplemenation>();
    }
}

public class JobFactory : IJobFactory {

    private IKernel Kernel { get; }

    public JobFactory(IKernel kernel)
    {
        Kernel = kernel;
    }

    public IJob GetJobInstance<T>() where T : IJob
    {
        return Kernel.Get<T>();
    }
}

Now you can start your jobs in main method by calling:

JobManager.JobFactory = new JobFactory(new StandardKernel(new MyNinjectModule()));
JobManager.Initialize(new JobRegistry());
like image 23
try2fly.b4ucry Avatar answered Nov 07 '22 01:11

try2fly.b4ucry