Quartz.NET+Topshelf 创建Windows服务
由于项目开发中经常会有定时任务执行的需求,所以会第一时间就想到 windows 服务 的方式,但是做过开发的同学都知道windows服务不利于调试,安装也麻烦;
并且有开源的作业框架Quartz.NET非常方便和好用,谁还愿意自己去写那些Timer定时器呢?既然选择用Quartz.NET,那怎么打包成一个Windows服务形式去运行呢?
那接下来就要引入Topshelf组件了。
Topshelf的使用
请查看博文地址:http://www.cnblogs.com/jys509/p/4614975.html
Quartz.NET和Topshelf的结合使用
请查看博文地址:https://www.cnblogs.com/jys509/p/4628926.html
由于上面2篇博文里面的组件版本都是较早的版本,所以本文重点介绍最新版本的应用案例:
第一步:安装
先建一个控制台项目JobServiceDemo,我用的是 .NET Framework 4.6.1,版本不低于4.5.2 就行
在NuGet中分别安装:log4net,Quartz,Quartz.Plugins,Topshelf,Topshelf.Log4Net 都选择最新版本,安装成功如下图:

第二步:实现Job
新建TestJob实现IJob接口,在Execute方法中实现自己的业务逻辑,代码如下:
using log4net;
using Quartz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace JobServiceDemo
{
public class TestJob : IJob
{
private readonly ILog _logger = LogManager.GetLogger(typeof(TestJob));
public Task Execute(IJobExecutionContext context)
{
_logger.Info("每3秒输出");
return Task.FromResult(true);
}
}
}
第三步:使用Topshelf调度任务
新建ServiceRunner服务运行类用于控制调度器的启动,停止,暂停,恢复运行4个接口方法,代码如下:
using Quartz;
using Quartz.Impl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Topshelf; namespace JobServiceDemo
{
public sealed class ServiceRunner : ServiceControl, ServiceSuspend
{
//调度器
private readonly IScheduler scheduler;
public ServiceRunner()
{
scheduler = StdSchedulerFactory.GetDefaultScheduler().GetAwaiter().GetResult();
}
//开始
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;
}
}
}
第四步:程序入口
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Topshelf; namespace JobServiceDemo
{
class Program
{
/// <summary>
/// 主程序入口
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{ log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(AppDomain.CurrentDomain.BaseDirectory + "log4net.config"));
HostFactory.Run(x =>
{
x.UseLog4Net(); x.Service<ServiceRunner>(s => {
s.ConstructUsing(name => new ServiceRunner());
s.WhenStarted((tc, hc) => tc.Start(hc));
s.WhenStopped((tc, hc) => tc.Stop(hc));
s.WhenContinued((tc, hc) => tc.Continue(hc));
s.WhenPaused((tc, hc) => tc.Pause(hc));
}); x.RunAsLocalService();
x.StartAutomaticallyDelayed(); x.SetDescription("用于系统定时任务计划执行");
x.SetDisplayName("JobService");
x.SetServiceName("JobService"); x.EnablePauseAndContinue();
});
}
}
}
第五步:配置quartz.config、quartz_jobs.xml、log4net.config
说明:这三个文件,分别选中→右键属性→复制到输入目录设为:始终复制
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.Plugins
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
<?xml version="1.0" encoding="UTF-8"?> <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> <!--测试任务配置-->
<job>
<name>TestJob</name>
<group>Test</group>
<description>测试任务</description>
<job-type>JobServiceDemo.TestJob,JobServiceDemo</job-type>
<durable>true</durable>
<recover>false</recover>
</job>
<trigger>
<cron>
<name>TestJobTrigger</name>
<group>TestTrigger</group>
<job-name>TestJob</job-name>
<job-group>Test</job-group>
<start-time>--04T00::+:</start-time>
<cron-expression>/ * * * * ?</cron-expression>
</cron>
</trigger> </schedule>
</job-scheduling-data>
log4net.config
<?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= "D:\JobServiceDemo\Log\"/>
<!--是否是向文件中追加日志-->
<param name= "AppendToFile" value= "true"/>
<!--log保留天数-->
<param name= "MaxSizeRollBackups" value= ""/>
<!--日志文件名是否是固定不变的-->
<param name= "StaticLogFileName" value= "false"/>
<!--日志文件名格式为:--.log-->
<param name= "DatePattern" value= "yyyy-MM-dd".log""/>
<!--日志根据日期滚动-->
<param name= "RollingStyle" value= "Date"/>
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n %loggername" />
</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>
运行后,效果下图,每隔3秒有输出

第六步:使用Topshelf安装成Windows服务运行
说明:cmd命令窗口一定要用管理员身份打开

Quartz.NET+Topshelf 创建Windows服务的更多相关文章
- 使用Topshelf创建Windows服务
		概述 Topshelf是创建Windows服务的另一种方法,老外的一篇文章Create a .NET Windows Service in 5 steps with Topshelf通过5个步骤详细的 ... 
- Topshelf创建Windows服务
		使用Topshelf创建Windows服务 概述 Topshelf是创建Windows服务的另一种方法,老外的一篇文章Create a .NET Windows Service in 5 steps ... 
- 【第三方插件】使用Topshelf创建Windows服务
		概述 Topshelf是创建Windows服务的另一种方法,老外的一篇文章Create a .NET Windows Service in 5 steps with Topshelf通过5个步骤详细的 ... 
- C#/.NET基于Topshelf创建Windows服务的守护程序作为服务启动的客户端桌面程序不显示UI界面的问题分析和解决方案
		本文首发于:码友网--一个专注.NET/.NET Core开发的编程爱好者社区. 文章目录 C#/.NET基于Topshelf创建Windows服务的系列文章目录: C#/.NET基于Topshelf ... 
- 使用Topshelf创建Windows服务[转载]
		概述 Topshelf是创建Windows服务的另一种方法,老外的一篇文章Create a .NET Windows Service in 5 steps with Topshelf通过5个步骤详细的 ... 
- 使用 Topshelf 创建 Windows 服务
		Ø 前言 C# 创建 Windows 服务的方式有很多种,Topshelf 就是其中一种方式,而且使用起来比较简单.下面使用 Visual Studio Ultimate 2013 演示一下具体的使 ... 
- [Solution] Microsoft Windows 服务(2) 使用Topshelf创建Windows服务
		除了通过.net提供的windows服务模板外,Topshelf是创建Windows服务的另一种方法. 官网教程:http://docs.topshelf-project.com/en/latest/ ... 
- 使用Topshelf创建Windows 服务
		本文转载: http://www.cnblogs.com/aierong/archive/2012/05/28/2521409.html http://www.cnblogs.com/jys509/p ... 
- Topshelf   创建windows服务注意事项
		其中项目应该是控制台应用程序 test.exe需要赋与管理员权限,右键属性可以定义. test.exe install test.exe unstall 
随机推荐
- ArcGIS Google Map 增加虚拟图层(MapImageLayer)(转载)
			<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="ht ... 
- FineReport中如何实现自动滚屏效果
			对于一些特殊的模板,可能为了展示的更加丰富.全面会在一个页面放置很多图表.表格等内容.由于内容过多,超出了浏览器窗口的大小导致内容展示不全的情况.这样我们就需要用到JS滚屏效果来解决,这里主要介绍在F ... 
- BitmapFactory.Options
			BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options(); bmpFactoryOptions.inSampleSiz ... 
- oracle 闪回功能详解
			Oracle的闪回技术提供了一组功能,可以访问过去某一时间的数据并从人为错误中恢复.闪回技术是Oracle 数据库独有的,支持任何级别的恢复,包括行.事务.表和数据库范围.使用闪回特性,您可以查询以前 ... 
- 从零开始导入gradle项目
			需要jdk1.8,idea17以上,电脑安装gradle(配置环境变量,与配置java类似),用git的push命令下项目,开始操作 gradle配置本地仓库位置:添加环境变量GRADLE_USER_ ... 
- 1. 跟踪标记 (Trace Flag) 1117, 1118 文件增长及空间分配方式
			跟踪标记:1117 功能: 默认,同一个文件组下的多个文件,如果某个文件没有可用空间,且设置了自动增长,则该文件自动增长,其他文件大小保持不变: 开启后,同一文件组下的多个文件,如果某个文件没有可用空 ... 
- [翻译] CBStoreHouseRefreshControl
			CBStoreHouseRefreshControl What is it? A fully customizable pull-to-refresh control for iOS inspired ... 
- [翻译] DBCamera 轻量级定制摄像头
			DBCamera 轻量级定制摄像头 https://github.com/danielebogo/DBCamera DBCamera is a simple custom camera with AV ... 
- Composer 的简介、安装及使用
			Composer的简介 简单说,Composer 就是一个安装包管理工具,服务于 PHP 生态系统.它包括了两个部分:Composer 和 Packagist. Composer Composer 是 ... 
- Hyper-v 中 CentOS 连接外网之有线网卡
			一.打开虚拟机交换管理器,查看默认的虚拟交换机 如果不是内部网络,则需要新建一个虚拟交换机,新的交换机应该使用内部网络: 二.配置虚拟机使用的交换机.如果 “默认开关” 不是内部网络,需要使用自己新创 ... 
 
			
		