在我们日常开发工作中,经常会运用到Quartz+Topshelf组件的组合来开发一些定时任务。那么在.Net Core下如何去使用呢?我自己尝试搭建了一个测试项目,过程中遇到了以下一些问题:
- Quartz 配置文件及版本问题。我们知道Quartz有2个配置文件,quartz.config和quartz.job.xml。前者负责组件初始化配置,后者负责job和triggle的配置。刚开始我是直接把framework下的配置文件直接拿过来用的,启动直接报错。主要问题在quartz.config
1
quartz.plugin.xml.type = Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz
这一段上。原因Quartz最新版本已经将Plugin模块单独剥离出一个独立的DLL,这里的引用也要变化。需要Nuget上下载Quartz.Plugins组件,并将上一段改成
1quartz.plugin.xml.type = Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz.Plugins
-
DI问题。为了贴合.Net Core DI精神,我们也要来实现Console程序的DI功能。第一个问题是Job如何DI?首先我们需要自己去实现JobFactory
12345678910111213141516171819public
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上下载的组件包(见后面项目结构截图)。加载方式如下
-
12345678
private
IConfiguration ConfigureConfiguration()
{
//配置文件
var
builder =
new
ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile(
"appsettings.json"
, optional:
false
, reloadOnChange:
true
);
return
builder.Build();
}
注入方式如下
12345678if
(configuration !=
null
)
{
//iconfiguration注入
services.AddSingleton<IConfiguration>(configuration);
}
//自定义 option方式注入
services.Configure<AppSetting>(configuration);
这样就可以在后续的类代码中 直接通过DI方式获取IConfiguration对象或者你自己的Option对象了
贴上完整代码。
Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 | 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 启动的核心
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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; } } |
项目结构截图
分类:
ASP.NET CORE
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类