Topshelf+Quartz在.Net Core框架下的實現
阿新 • • 發佈:2019-11-06
在我們日常開發工作中,經常會運用到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.dotnet