在我們日常開發工作中,經常會運用到Quartz+Topshelf組件的組合來開發一些定時任務。那麼在.Net Core下如何去使用呢?我自己嘗試搭建了一個測試項目,過程中遇到了以下一些問題:
- Quartz 配置文件及版本問題。我們知道Quartz有2個配置文件,quartz.config和quartz.job.xml。前者負責組件初始化配置,後者負責job和triggle的配置。剛開始我是直接把framework下的配置文件直接拿過來用的,啓動直接報錯。主要問題在quartz.config
quartz.plugin.xml.type = Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz
這一段上。原因Quartz最新版本已經將Plugin模塊單獨剝離出一個獨立的DLL,這裏的引用也要變化。需要Nuget上下載Quartz.Plugins組件,並將上一段改成
quartz.plugin.xml.type = Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz.Plugins
-
DI問題。爲了貼合.Net Core DI精神,我們也要來實現Console程序的DI功能。第一個問題是Job如何DI?首先我們需要自己去實現JobFactory
public class NewJobFactory : IJobFactory { private readonly IServiceProvider _serviceProvider; public NewJobFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler) { return _serviceProvider.GetService(bundle.JobDetail.JobType) as IJob; } public void ReturnJob(IJob job) { var disposable = job as IDisposable; disposable?.Dispose(); } }
注入方式
IServiceCollection services = new ServiceCollection(); services.AddScoped<IJobFactory, NewJobFactory>(); services.AddSingleton(service => { var scheduler = StdSchedulerFactory.GetDefaultScheduler().Result; scheduler.JobFactory = service.GetService<IJobFactory>(); return scheduler; });
- Console程序的配置文件獲取以及注入問題。衆所周知,.Net Core下建立的Console程序就是一塊白板,什麼都沒有。配置文件我們還得自己去建一個.json文件。並且需要自己從Nuget上下載的組件包(見後面項目結構截圖)。加載方式如下
-
private IConfiguration ConfigureConfiguration() { //配置文件 var builder = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); return builder.Build(); }
注入方式如下
if (configuration != null) { //iconfiguration注入 services.AddSingleton<IConfiguration>(configuration); } //自定義 option方式注入 services.Configure<AppSetting>(configuration);
這樣就可以在後續的類代碼中 直接通過DI方式獲取IConfiguration對象或者你自己的Option對象了
貼上完整代碼。
Program.cs
static void Main(string[] args)
{
HostFactory.Run(x =>
{
x.Service<ServiceRunner>();
x.SetDescription("gt.dotnetcore.consolesample");
x.SetDisplayName("gt.dotnetcore.consolesample");
x.SetServiceName("gt.dotnetcore.consolesample");
x.StartAutomatically();
});
}
ServiceRunner.cs 啓動的核心
public class ServiceRunner : ServiceControl
{
//private readonly IScheduler _scheduler;
private IServiceProvider _serviceProvider;
public ServiceRunner()
{
var configurationRoot = ConfigureConfiguration();
_serviceProvider = ConfigureServices(configurationRoot);
}
private IConfiguration ConfigureConfiguration()
{
//配置文件
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
return builder.Build();
}
private IServiceProvider ConfigureServices(IConfiguration configuration)
{
//依賴注入
IServiceCollection services = new ServiceCollection();
//後續需要使用log的話,這裏需要注入
services.AddTransient<ILoggerFactory, LoggerFactory>();
services.AddTransient<ITest, TestBiz>();
services.AddScoped<IJobFactory, NewJobFactory>();
if (configuration != null)
{
//iconfiguration注入
services.AddSingleton<IConfiguration>(configuration);
}
//自定義 option方式注入
services.Configure<AppSetting>(configuration);
//這裏注意Job的注入方式,不要強制指定IJob實現方式!!
services.AddScoped<TestJob>();
services.AddScoped<Test2Job>();
services.AddSingleton(service =>
{
var scheduler = StdSchedulerFactory.GetDefaultScheduler().Result;
scheduler.JobFactory = service.GetService<IJobFactory>();
return scheduler;
});
//構建容器
return services.BuildServiceProvider();
}
public bool Start(HostControl hostControl)
{
var scheduler = _serviceProvider.GetService(typeof(IScheduler)) as IScheduler;
scheduler.Start();
return true;
}
public bool Stop(HostControl hostControl)
{
var scheduler = _serviceProvider.GetService(typeof(IScheduler)) as IScheduler;
scheduler.Shutdown(true);
return true;
}
}
Test2Job.cs
public class Test2Job : IJob
{
private ITest _testService;
private AppSetting _appsetting;
private IConfiguration _configuration;
public Test2Job(ITest testService, IOptionsMonitor<AppSetting> appSettingAccessor, IConfiguration configuration)
{
_testService = testService;
_appsetting = appSettingAccessor.CurrentValue;
_configuration = configuration;
}
public Task Execute(IJobExecutionContext context)
{
Console.WriteLine($"job2222222222222 started:{_appsetting.TestCN}");
var t = _testService.Dowork(1);
t.Wait();
Console.WriteLine($"job2222222222222 ended:{_configuration["TestCN"]}");
return Task.CompletedTask;
}
}
項目結構截圖
附項目源碼 https://gitee.com/gt1987/gt.dotnetcore
原文出處:https://www.cnblogs.com/gt1987/p/11806053.html