在我们日常开发工作中,经常会运用到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

Topshelf+Quartz在.Net Core框架下的实现的更多相关文章

  1. 分别在.NET Framework 与 .NET Core 框架下 编写Windows Service(windows服务程序)

    前言,为什么会分别在两个框架下编写Windows Service,是因为最近在做区块链这块,使用的是NEO(小蚁区块链)的相关技术,NEO使用的是.net core 2.1,业务上需要写两个程序,一个 ...

  2. .net core+topshelf+quartz创建windows定时任务服务

    .net core+topshelf+quartz创建windows定时任务服务 准备工作 创建.net core 控制台应用程序,这里不做过多介绍 添加TopShelf包:TopShelf: 添加Q ...

  3. 微服务框架下的思维变化-OSS.Core基础思路

    如今框架两字已经烂大街了,xx公司架构设计随处可见,不过大多看个热闹,这些框架如何来的,细节又是如何思考的,相互之间的隔离依据又是什么...相信很多朋友应该依然存在自己的疑惑,特别是越来越火热的微服务 ...

  4. Windows Forms和WPF在Net Core 3.0框架下并不会支持跨平台

    Windows Forms和WPF在Net Core 3.0框架下并不会支持跨平台 微软将WinForms和WPF带到.NET Core 3.0这一事实,相信大家都有所了解,这是否意味着它在Linux ...

  5. C# 6 与 .NET Core 1.0 高级编程 - 40 ASP.NET Core(下)

    译文,个人原创,转载请注明出处(C# 6 与 .NET Core 1.0 高级编程 - 40 章  ASP.NET Core(下)),不对的地方欢迎指出与交流. 章节出自<Professiona ...

  6. 一个Mini的ASP.NET Core框架的实现

    一.ASP.NET Core Mini 在2019年1月的微软技术(苏州)俱乐部成立大会上,蒋金楠老师(大内老A)分享了一个名为“ASP.NET Core框架揭秘”的课程,他用不到200行的代码实现了 ...

  7. 200行代码,7个对象——让你了解ASP.NET Core框架的本质

    2019年1月19日,微软技术(苏州)俱乐部成立,我受邀在成立大会上作了一个名为<ASP.NET Core框架揭秘>的分享.在此次分享中,我按照ASP.NET Core自身的运行原理和设计 ...

  8. Spring Security框架下Restful Token的验证方案

    项目使用Restful的规范,权限内容的访问,考虑使用Token验证的权限解决方案. 验证方案(简要概括): 首先,用户需要登陆,成功登陆后返回一个Token串: 然后用户访问有权限的内容时需要上传T ...

  9. Spring 框架下 (增 删 改 )基本操作

    //applicationContext.xml 配置文件 <?xml version="1.0" encoding="UTF-8"?><be ...

随机推荐

  1. Flask基础(03)-->创建第一个Flask程序

    # 导入Flask from flask import Flask # 创建Flask的应用程序 # 参数__name__指的是Flask所对应的模块,其决定静态文件从哪个地方开始寻找 app = F ...

  2. 005-做题:使用 Python 生成 200 个激活码

    题目:使用 Python 生成 200 个不重复的激活码 编写思路# 激活码一般是由26个大写字母和10个数字任意组合而成# 长度为12位或者16位的居多激活码# 一个激活码里的字符是可以重复的,而且 ...

  3. mybatis - 通用mapper

    title: 玩转spring-boot-mybatis date: 2019-03-11 19:36:57 type: "mybatis" categories: mybatis ...

  4. Zeppelin 学习笔记之 Zeppelin安装和elasticsearch整合

    Zeppelin安装: Apache Zeppelin提供了web版的类似ipython的notebook,用于做数据分析和可视化.背后可以接入不同的数据处理引擎,包括spark, hive, taj ...

  5. 本次作业统一标题:C语言I博客作业02

    这个作业属于哪个课程 C语言程序设计1 这作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/CST2019-2/homework/8655 我在这个课程的目标是 ...

  6. 初探内核之《Linux内核设计与实现》笔记上

    内核简介  本篇简单介绍内核相关的基本概念. 主要内容: 单内核和微内核 内核版本号 1. 单内核和微内核   原理 优势 劣势 单内核 整个内核都在一个大内核地址空间上运行. 1. 简单.2. 高效 ...

  7. Qt5教程: (8) 标准对话框和文件对话框

    1. about对话框 包含头文件 #include <QMessageBox> 添加菜单项 QAction *p3 = pDialog->addAction("关于&qu ...

  8. pycharm2018.2汉化 解决设置打不开问题

    首先检查下是不是装了中文汉化包resources_cn.jar 如果有的话,解决办法:1.更换一个汉化包或者将原来的resources_en.jar也放进lib目录下 2.将汉化包都删除,只留下原版的 ...

  9. Neo4j:图数据库GraphDB(一)入门和基本查询语句

    图数据库的代表:Neo4j 官网:  http://neo4j.com/ 引言:为什么使用图数据库 在很多新型项目中,应用图数据库已经是势在必行的趋势了,因为图数据库可以很好的表示各种节点与关系的概念 ...

  10. [BZOJ1694/1742/3074]The Cow Run 三倍经验

    Description John养了一只叫Joseph的奶牛.一次她去放牛,来到一个非常长的一片地,上面有N块地方长了茂盛的草.我们可 以认为草地是一个数轴上的一些点.Joseph看到这些草非常兴奋, ...