Quartz:首先我贴出来了两段代码(下方),可以看出,首先会根据配置文件(quartz.config),包装出一个Quartz.Core.QuartzScheduler

instance,这是一个调度器,调度各个任务项(Jobs)的执行。这个调度器可以被Start、被Shutdown、被PauseAll、被ResumeAll,这对应

了windows服务的开启、停止、暂停、恢复。当启动服务,我就调用调度器的Start(),停止服务我就调用调度器的Shutdown()方法。

namespace QTDemo
{
public class ServiceRunner : ServiceControl, ServiceSuspend
{
private readonly IScheduler scheduler; public ServiceRunner()
{
scheduler = StdSchedulerFactory.GetDefaultScheduler();
} public bool Start(HostControl hostControl)
{
scheduler.Start();
return true;
}
// 摘要:
// An implementation of Quartz.ISchedulerFactory that does all of it's work
// of creating a Quartz.Core.QuartzScheduler instance based on the contents
// of a properties file.
public class StdSchedulerFactory : ISchedulerFactory
{
public const string AutoGenerateInstanceId = "AUTO";
public const string ConfigurationSectionName = "quartz";
public const string DefaultInstanceId = "NON_CLUSTERED";
public const string PropertiesFile = "quartz.config";

  那TopShelf又扮演了什么样的角色呢

  这是一个宿主服务的框架。和ServiceBase、ServiceInstaller那一套的目的一样,都是用来创建Windows服务的。

项目示例

1、新建项目控制台应用程序‘QTDemo’

2、从NuGet安装‘Quartz’,‘Topshelf’,‘Topshelf.Log4Net’

 <?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Common.Logging" version="3.3.1" targetFramework="net45" />
<package id="Common.Logging.Core" version="3.3.1" targetFramework="net45" />
<package id="log4net" version="2.0.5" targetFramework="net45" />
<package id="Quartz" version="2.3.3" targetFramework="net45" />
<package id="Topshelf" version="3.3.1" targetFramework="net45" />
<package id="Topshelf.Log4Net" version="3.3.1" targetFramework="net45" />
</packages>

3、定义一个Job(一个任务项),继承Quartz.IJob

 using Quartz;
namespace QTDemo.QuartzJobs
{
public sealed class TestJob : IJob
{
public void Execute(IJobExecutionContext context)
{
CommonHelper.AppLogger.InfoFormat("TestJob测试"); }
}
}

4、配置(新建)quartz.config、quartz_jobs.xml

quartz.config可直接使用,不用修改

 # You can configure your scheduler in either <quartz> configuration section
# or in quartz properties file
# Configuration section has precedence quartz.scheduler.instanceName = QuartzTest # configure thread pool info
quartz.threadPool.type = Quartz.Simpl.SimpleThreadPool, Quartz
quartz.threadPool.threadCount =
quartz.threadPool.threadPriority = Normal # job initialization plugin handles our xml reading, without it defaults are used
quartz.plugin.xml.type = Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz
quartz.plugin.xml.fileNames = ~/quartz_jobs.xml # export this server to remoting context
#quartz.scheduler.exporter.type = Quartz.Simpl.RemotingSchedulerExporter, Quartz
#quartz.scheduler.exporter.port =
#quartz.scheduler.exporter.bindName = QuartzScheduler
#quartz.scheduler.exporter.channelType = tcp
#quartz.scheduler.exporter.channelName = httpQuartz

quartz_jobs.xml根据实际的Job项修改

 <?xml version="1.0" encoding="utf-8" ?>
<!-- This file contains job definitions in schema version 2.0 format --> <job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0"> <processing-directives>
<overwrite-existing-data>true</overwrite-existing-data>
</processing-directives> <schedule> <!--TestJob测试 任务配置 -->
<job>
<name>TestJob</name>
<group>Test</group>
<description>TestJob测试</description>
<job-type>QTDemo.QuartzJobs.TestJob,QTDemo</job-type>
<durable>true</durable>
<recover>false</recover>
</job>
<trigger>
<cron>
<name>TestJobTrigger</name>
<group>Test</group>
<job-name>TestJob</job-name>
<job-group>Test</job-group>
<!-- 从start-time起,每5s执行一次IJob.Execute -->
<start-time>2012-01-22T00:00:00+08:00</start-time>
<cron-expression>0/5 * * * * ?</cron-expression>
</cron>
</trigger> </schedule>
</job-scheduling-data>

5、创建服务

入口:

 using System;
using System.IO;
using Topshelf; namespace QTDemo
{
class Program
{
static void Main(string[] args)
{
log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(AppDomain.CurrentDomain.BaseDirectory + "log4net.config")); HostFactory.Run(x =>
{
x.UseLog4Net(); x.Service<ServiceRunner>(); x.RunAsLocalSystem(); x.SetDescription("Quartz+TopShelf实现Windows服务作业调度的一个示例Demo");
x.SetDisplayName("QuartzTopShelfDemo服务");
x.SetServiceName("QuartzTopShelfDemoService"); x.EnablePauseAndContinue(); });
}
}
}

ServiceRunner.cs

 using Quartz;
using Quartz.Impl;
using Topshelf; namespace QTDemo
{
public class ServiceRunner : ServiceControl, ServiceSuspend
{
private readonly IScheduler scheduler; public ServiceRunner()
{
scheduler = StdSchedulerFactory.GetDefaultScheduler();
} public bool Start(HostControl hostControl)
{
scheduler.Start();
return true;
} public bool Stop(HostControl hostControl)
{
scheduler.Shutdown(false);
return true;
} public bool Continue(HostControl hostControl)
{
scheduler.ResumeAll();
return true;
} public bool Pause(HostControl hostControl)
{
scheduler.PauseAll();
return true;
} }
}

log4net配置文件,可直接使用

 <?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections> <log4net>
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<!--日志路径-->
<param name= "File" value= "Log\"/>
<!--是否是向文件中追加日志-->
<param name= "AppendToFile" value= "true"/>
<!--log保留天数-->
<param name= "MaxSizeRollBackups" value= "10"/>
<!--日志文件名是否是固定不变的-->
<param name= "StaticLogFileName" value= "false"/>
<!--日志文件名格式为:2008-08-31.log-->
<param name= "DatePattern" value= "yyyy-MM-dd&quot;.read.log&quot;"/>
<!--日志根据日期滚动-->
<param name= "RollingStyle" value= "Date"/>
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%date{HH:mm:ss,fff} %-5p-%m%n" />
</layout>
</appender> <!-- 控制台前台显示日志 -->
<appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
<mapping>
<level value="ERROR" />
<foreColor value="Red, HighIntensity" />
</mapping>
<mapping>
<level value="Info" />
<foreColor value="Green" />
</mapping>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%n%date{HH:mm:ss,fff} [%-5level] %m" />
</layout> <filter type="log4net.Filter.LevelRangeFilter">
<param name="LevelMin" value="Info" />
<param name="LevelMax" value="Fatal" />
</filter>
</appender> <root>
<!--(高) OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL (低) -->
<level value="all" />
<appender-ref ref="ColoredConsoleAppender"/>
<appender-ref ref="RollingLogFileAppender"/>
</root> </log4net>
</configuration>

6、quartz.config、quartz_jobs.xml、log4net.config都设置成‘始终复制’

7、直接F5,调试,发现TestJob每5s执行一次

8、安装成Windows服务

用Release编一个版本

然后用命令行安装服务

服务面板里可以找到此服务

启动之,查看日志文件,服务运行正常

::, INFO -Configuration Result:
[Success] Name QuartzTopShelfDemoService
[Success] DisplayName QuartzTopShelfDemo服务
[Success] Description Quartz+TopShelf实现Windows服务作业调度的一个示例Demo
[Success] ServiceName QuartzTopShelfDemoService
::, INFO -Topshelf v3.3.154., .NET Framework v4.0.30319.
::, ERROR-The QuartzTopShelfDemoService service can only be installed as an administrator
::, INFO -Configuration Result:
[Success] Name QuartzTopShelfDemoService
[Success] DisplayName QuartzTopShelfDemo服务
[Success] Description Quartz+TopShelf实现Windows服务作业调度的一个示例Demo
[Success] ServiceName QuartzTopShelfDemoService
::, INFO -Topshelf v3.3.154., .NET Framework v4.0.30319.
::, DEBUG-Attempting to install 'QuartzTopShelfDemoService'
::, INFO -Installing QuartzTopShelfDemo服务 service
::, DEBUG-Opening Registry
::, DEBUG-Service path: "E:\DotNetProject\Y2016\QTDemo\QTDemo\bin\Release\QTDemo.exe"
::, DEBUG-Image path: "E:\DotNetProject\Y2016\QTDemo\QTDemo\bin\Release\QTDemo.exe" -displayname "QuartzTopShelfDemo服务" -servicename "QuartzTopShelfDemoService"
::, DEBUG-Closing Registry
::, INFO -Configuration Result:
[Success] Name QuartzTopShelfDemoService
[Success] DisplayName QuartzTopShelfDemo服务
[Success] Description Quartz+TopShelf实现Windows服务作业调度的一个示例Demo
[Success] ServiceName QuartzTopShelfDemoService
::, INFO -Topshelf v3.3.154., .NET Framework v4.0.30319.
::, DEBUG-Started by the Windows services process
::, DEBUG-Running as a service, creating service host.
::, INFO -Starting as a Windows service
::, DEBUG-[Topshelf] Starting up as a windows service application
::, INFO -[Topshelf] Starting
::, DEBUG-[Topshelf] Current Directory: E:\DotNetProject\Y2016\QTDemo\QTDemo\bin\Release
::, DEBUG-[Topshelf] Arguments:
::, INFO -[Topshelf] Started
::, INFO -TestJob测试
::, INFO -TestJob测试
::, INFO -TestJob测试

  附:源码下载

Quartz+TopShelf实现Windows服务作业调度的更多相关文章

  1. Quartz和TopShelf Windows服务作业调度

    上一次写了一遍关于Quartz作业调度的文章 Quartz.NET 作业调度使用 现在使用TopShelf和Quartz实现windows服务作业调度 TopShelf版本4.0 Quartz版本3. ...

  2. 使用 Topshelf 结合 Quartz.NET 创建 Windows 服务

    Ø  前言 之前一篇文章已经介绍了,如何使用 Topshelf 创建 Windows 服务.当时提到还缺少一个任务调度框架,就是 Quartz.NET.而本文就展开对 Quartz.NET 的研究,以 ...

  3. 使用Topshelf创建Windows服务

    概述 Topshelf是创建Windows服务的另一种方法,老外的一篇文章Create a .NET Windows Service in 5 steps with Topshelf通过5个步骤详细的 ...

  4. Topshelf创建Windows服务

    使用Topshelf创建Windows服务 概述 Topshelf是创建Windows服务的另一种方法,老外的一篇文章Create a .NET Windows Service in 5 steps ...

  5. 【第三方插件】使用Topshelf创建Windows服务

    概述 Topshelf是创建Windows服务的另一种方法,老外的一篇文章Create a .NET Windows Service in 5 steps with Topshelf通过5个步骤详细的 ...

  6. C# DateTime的11种构造函数 [Abp 源码分析]十五、自动审计记录 .Net 登陆的时候添加验证码 使用Topshelf开发Windows服务、记录日志 日常杂记——C#验证码 c#_生成图片式验证码 C# 利用SharpZipLib生成压缩包 Sql2012如何将远程服务器数据库及表、表结构、表数据导入本地数据库

    C# DateTime的11种构造函数   别的也不多说没直接贴代码 using System; using System.Collections.Generic; using System.Glob ...

  7. C#/.NET基于Topshelf创建Windows服务的守护程序作为服务启动的客户端桌面程序不显示UI界面的问题分析和解决方案

    本文首发于:码友网--一个专注.NET/.NET Core开发的编程爱好者社区. 文章目录 C#/.NET基于Topshelf创建Windows服务的系列文章目录: C#/.NET基于Topshelf ...

  8. 使用Topshelf创建Windows服务[转载]

    概述 Topshelf是创建Windows服务的另一种方法,老外的一篇文章Create a .NET Windows Service in 5 steps with Topshelf通过5个步骤详细的 ...

  9. Quartz.NET+Topshelf 创建Windows服务

    由于项目开发中经常会有定时任务执行的需求,所以会第一时间就想到 windows 服务 的方式,但是做过开发的同学都知道windows服务不利于调试,安装也麻烦: 并且有开源的作业框架Quartz.NE ...

随机推荐

  1. O(n)线性空间的迷宫生成算法

    之前所有的迷宫生成算法,空间都是O(mn),时间同样是O(mn),时间上已经不可能更优化, 于是,我就从空间优化上着手,研究一个仅用O(n)空间的生成算法. 我初步的想法是,每次生成一行,生成后立即输 ...

  2. 二、Jmeter录制脚本过程及Could not create script recorder报错、您的连接不是私密连接报错

    两个报错:Could not create script recorder报错和您的连接不是私密连接报错 1.录制过程 * 打开jmeter * 点击Templated,选择Recoding模版 * ...

  3. 常见企业IT支撑【6、跳板机Jumpserver】

    Jumpserver是国内一款开源的轻便的跳板机系统,他们的官网:http://www.jumpserver.org/ 使用这款软件意在提高公司内部登录生产环境服务器的便捷性,权限分配细化,以及后台管 ...

  4. dedecms问答模块时间显示1970-01-01的解决办法

    在使用dedecms的问答模块的时候,很多人希望能在模板上加上问题的时间,一般我们采用这样的dede标签: {dede:ask row=24 titlelen='50' sort='ok'}   &l ...

  5. box-shadow 边框样式

    如下 box-shadow: 0 1px 3px 0 rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 2px 1px -1px rgba(0,0,0,.1 ...

  6. <<APUE>> 线程的分离状态

    在任何一个时间点上,线程是可结合的(joinable),或者是分离的(detached).一个可结合的线程能够被其他线程收回其资源和杀死:在被其他线程回收之前,它的存储器资源(如栈)是不释放的.相反, ...

  7. Zabbix 命令:zabbix_get

    zabbix_get 作用总有人在群里提问,为什么 zabbix 获取不到数据,为什么 zabbix 提示 Not Support,怎么办?别老问,用 zabbix_get 试着获取数据即可.在 za ...

  8. 字符串strip相关函数

    s.strip(rm) 删除s字符串中开头.结尾处,位于 rm删除序列的所有字符,但只要遇到非rm序列中的字符就停止s.lstrip(rm) 删除s字符串中开头处,位于 rm删除序列的所有字符,,但只 ...

  9. 用javascript/jQuery给CKEditor取值/赋值

    CKEditor 是著名的 HTML 编辑器,IBM.Oracle.Adobe 等都在用.CKEditor 创建于 2003 年,其前身为 FCKEditor,在 2009 年的时候把“F”去掉了,更 ...

  10. javascript callee和caller

    arguments的主要用途是保存参数,但是他还有callee属性. 一:callee指向arguments对象的函数. 示例一: function calture(num) {//阶乘计算 if ( ...