我目前使用ASP.NET Core MVC(.NET 4.6.1)进行简单的网站设置,我想定期做一些过程,比如每天结束时自动向注册会员发送电子邮件。
在做了一些搜索之后,我遇到了两个常见的解决方案 - Quartz.NET和FluentScheduler。
基于此SO thread,我发现使用FluentScheduler的方法更容易消化并用于我的简单任务。在我的Program.cs类中快速实现以下代码行后,我每分钟都成功发送电子邮件(用于测试目的)。
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();
}
}
然而,除了发送电子邮件之外,我还需要进行一些后端处理,例如在发送邮件时更新数据库中的用户记录。为此,我通常将我的实体框架上下文注入我的控制器的构造函数中,并使用它来获取/更新SQL记录。
我的问题是,因为我无法将这些服务真正地注入到main方法中,所以在哪里可以初始化注册表并为调度添加作业?
感谢您的帮助,我对此有点新意,所以我会非常感谢您的一点指导!
答案 0 :(得分:2)
而不是程序的主要功能,我在app.UseMvc之前在Startup.cs中初始化了它。
public void Configure(...., IDependencyObject dependencyObject)
{
....
JobManager.Initialize(new MyRegistry(dependencyObject));
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "api/{controller}/{action}/{id?}");
});
}
我的注册表类看起来像这样:
public class MyRegistry: Registry
{
public MyRegistry(IDependencyObject dependencyObject)
{
Schedule(() => new SyncUpJob(dependencyObject)).ToRunNow().AndEvery(10).Seconds();
}
}
我的Job类看起来像这样:
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
}
}
答案 1 :(得分:1)
您可以通过FluentScheduler Registry
类的子类化来定义所有作业及其日程表。类似的东西:
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
}
}
要将依赖项注入作业,您需要实现FluentScheduler IJobFactory
接口。 FluentScheduler调用GetJobIntance
方法来创建作业实例。在这里,您可以使用任何您想要的DI库;在此示例实现中,我将假设您使用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>();
}
}
现在,您可以通过调用以下方法在main方法中启动作业:
JobManager.JobFactory = new JobFactory(new StandardKernel(new MyNinjectModule()));
JobManager.Initialize(new JobRegistry());