使用Topshelf
开发Windows服务,比起直接写Windows服务的优势在于,可以直接运行调试。开发完成后,直接使用install
命令注册为服务即可,简单高效。
一、准备工作
-
创建一个控制台应用
image.png -
在Nuget包管理器中搜索并安装Topshelf、Quartz、log4net这几个库
image.png
使用Topshelf框架
- 在程序入口类
Program.cs
中修改Main方法
using Topshelf;
namespace DemoService
{
class Program
{
static void Main(string[] args)
{
string serviceName = "DemoService";
HostFactory.Run(config =>
{
config.Service<StartService>(s =>
{
s.ConstructUsing(name => new StartService());
s.WhenStarted(service => service.Start());
s.WhenStopped(service => service.Stop());
});
config.RunAsLocalSystem();
config.SetDescription(serviceName);
config.SetServiceName(serviceName);
config.SetDisplayName(serviceName);
});
}
}
}
- 新增类文件:
StartService.cs
,并编写Start()、Stop()方法,这两个方法在Main方法中被注册为服务的启动和停止方法。
namespace DemoService
{
public class StartService
{
public void Start()
{
}
public void Stop()
{
}
}
}
二、配置日志工具log4net
-
创建一个应用程序配置文件,改名为
image.pnglog4net.config
-
在
log4net.config
的<configuration>
项中写入如下配置项
<!-- Level的级别,由高到低 -->
<!-- None > Fatal > ERROR > WARN > DEBUG > INFO > ALL-->
<!-- 解释:如果level是ERROR,则在cs文件里面调用log4net的info()方法,则不会写入到日志文件中-->
<log4net>
<!--错误日志类-->
<logger name="logerror"><!--日志类的名字-->
<level value="ALL" /><!--定义记录的日志级别-->
<appender-ref ref="ErrorAppender" /><!--记录到哪个介质中去-->
</logger>
<!--信息日志类-->
<logger name="loginfo">
<level value="ALL" />
<appender-ref ref="InfoAppender" />
</logger>
<!--错误日志附加介质-->
<appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender"><!-- name属性指定其名称,type则是log4net.Appender命名空间的一个类的名称,意思是,指定使用哪种介质-->
<param name="File" value="Log\\LogError\\" /><!--日志输出到exe程序这个相对目录下-->
<param name="AppendToFile" value="true" /><!--输出的日志不会覆盖以前的信息-->
<param name="MaxSizeRollBackups" value="100" /><!--备份文件的个数-->
<param name="MaxFileSize" value="10240" /><!--当个日志文件的最大大小-->
<param name="StaticLogFileName" value="false" /><!--是否使用静态文件名-->
<param name="DatePattern" value=""Log_"yyyyMMdd".htm"" /><!--日志文件名-->
<param name="RollingStyle" value="Date" /><!--文件创建的方式,这里是以Date方式创建-->
<!--错误日志布局-->
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="<HR COLOR=red>%n异常时间:%d [%t] <BR>%n异常级别:%-5p <BR>%n异 常 类:%c [%x] <BR>%n%m <BR>%n <HR Size=1>" />
</layout>
</appender>
<!--信息日志附加介质-->
<appender name="InfoAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="Log\\LogInfo\\" />
<param name="AppendToFile" value="true" />
<param name="MaxFileSize" value="10240" />
<param name="MaxSizeRollBackups" value="100" />
<param name="StaticLogFileName" value="false" />
<param name="DatePattern" value=""Log_"yyyyMMdd".htm"" />
<param name="RollingStyle" value="Date" />
<!--信息日志布局-->
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="<HR COLOR=blue>%n日志时间:%d [%t] <BR>%n日志级别:%-5p <BR>%n日 志 类:%c [%x] <BR>%n%m <BR>%n <HR Size=1>" />
</layout>
</appender>
</log4net>
-
以上配置将会将Info日志保存至项目文件夹下的
转义字符对照表Log\\LogInfo\\
,将错误日志保存至Log\\LogError\\
,日志文件保存为.htm
格式。
日志效果图 -
在
Properties
下的AssemblyInfo.cs
中注册一下log4net.config
配置文件
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", ConfigFileExtension = "config", Watch = true)]
- 编写
LogHelper.cs
类
public class LogHelper
{
//这里的 loginfo 和 log4net.config 里的名字要一样
private static readonly log4net.ILog loginfo = log4net.LogManager.GetLogger("loginfo");
//这里的 logerror 和 log4net.config 里的名字要一样
private static readonly log4net.ILog logerror = log4net.LogManager.GetLogger("logerror");
public static void Info(string message)
{
if (loginfo.IsInfoEnabled)
{
loginfo.Info(message);
}
}
public static void Error(string message, Exception ex)
{
if (logerror.IsErrorEnabled)
{
logerror.Error(message, ex);
}
}
}
三、使用Quartz编写定时任务
- 创建一个
DemoJob.cs
类
using Quartz;
using System;
namespace DemoService.Jobs
{
public class DemoJob : IJob
{
public void Execute(IJobExecutionContext context)
{
Console.WriteLine("Hello");
LogHelper.Info("Hello");
}
}
}
- 使用Quartz框架,打开
StartService.cs
文件,在Start()方法中添加如下内容
public class StartService
{
public void Start()
{
// 开启调度
ISchedulerFactory sf = new StdSchedulerFactory();
IScheduler scheduler = sf.GetScheduler();
IJobDetail job = JobBuilder.Create<DemoJob>().Build();
// 服务启动时执行一次
// ITrigger triggerNow = TriggerBuilder.Create().StartNow().Build();
// 每日22点执行一次
ITrigger trigger = TriggerBuilder.Create()
.StartNow()
.WithCronSchedule("0 0 22 1/1 * ? ")
.Build();
scheduler.ScheduleJob(job, trigger);
scheduler.Start();
LogHelper.Info("服务开始执行。");
}
public void Stop()
{
}
}
-
Cron
表达式很强大,但刚上手需要一定的学习成本,此处附上一个生成表达式的工具:
在线Cron表达式生成器传送门 -
想了解
Cron
表达式,可参考该篇博文:https://www.cnblogs.com/yanghj010/p/10875151.html
四、服务注册、卸载
编写如下两个批处理文件,放在生成的目录下,需要注册、卸载时,直接执行即可。
install.bat
cd /d "%~dp0"
生成的可执行文件名.exe install
net start DemoService
cmd
uninstall.bat
cd /d "%~dp0"
生成的可执行文件名.exe uninstall
cmd
网友评论