.NET Framework之Windows服务
一、背景
项目中要实现一个定时任务的需求,目前C#定时任务的框架有很多比如Hangfire、Quartz.net等,其中Hangfire提供可视化的面板、重试操作并且其可以寄宿在各种宿主应用程序中。但是项目是要定时获取其他系统数据到本系统,功能简单,所以为了不引入太复杂的框架和增加学习成本的考虑,使用微软提供的windows服务应用程序结合Timer组件来完成该需求。通过项目的使用过程对windows服务应用程序加深认识、实际应用的实践进行总结一下。
二、定义
Microsoft Windows 服务(过去称为 NT 服务)允许用户创建可在其自身的 Windows 会话中长时间运行的可执行应用程序。 这些服务可在计算机启动时自动启动,可以暂停和重启,并且不显示任何用户界面。 这些功能使服务非常适合在服务器上使用,或者需要长时间运行的功能(不会影响在同一台计算机上工作的其他用户)的情况。 还可以在与登录用户或默认计算机帐户不同的特定用户帐户的安全性上下文中运行服务。
我们电脑的任务管理器中服务项,包含系统正在运行和已停止的后台服务,其是无可视化界面,通过设置服务属性中启动类型(自动、手动、禁用、延迟),自动是系统启动的时候相应的服务也会自动启动。
三、使用
1、创建服务,在VS中创建一个windows服务应用程序、选择相应框架版本、在解决方案中会生成对应名称的服务设计窗体,通过属性设置服务名称等项。在代码中包含OnStart和OnStop方法,就是服务的启动和停止方法,在相应的方法中加入业务逻辑,在设计器中引入Timer组件,Timer组件是基于服务器的计时器,它允许指定在 Elapsed 应用程序中引发事件的重复间隔。 然后,你可以处理此事件以提供常规处理。通过Timer组件的Elapsed的产生时间达到定时任务的效果。
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 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | using Comm; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Linq; using System.ServiceProcess; using System.Text; using System.Threading.Tasks; using ZTDataPullService.BLL.CdpApiService; using Newtonsoft.Json; namespace ZTDataPullService { /// <summary> /// 中台拉取数据定时任务服务 /// </summary> public partial class ZTDataPullService : ServiceBase { //定义一个时钟 System.Timers.Timer timer = new System.Timers.Timer(); private readonly OrgBll bll = new OrgBll(); MyLog logger = new MyLog(); public ZTDataPullService() { InitializeComponent(); } /// <summary> /// 开始服务 /// </summary> /// <param name="args"></param> protected override void OnStart( string [] args) { logger.Info( typeof (ZTDataPullService), JsonConvert.SerializeObject(args)); //logger.Info(typeof(ZTDataPullService), "开始服务"); timer.Interval = 60000; //执行间隔时间,单位为毫秒;此时时间间隔为1分钟 timer.AutoReset = true ; //执行一次 false,一直执行true timer.Enabled = true ; //是否执行System.Timers.Timer.Elapsed事件 timer.Start(); timer.Elapsed += new System.Timers.ElapsedEventHandler(PullDataHandler); } /// <summary> /// 拉取中台的数据 /// </summary> /// <param name="source"></param> /// <param name="e"></param> public void PullDataHandler( object source, System.Timers.ElapsedEventArgs e) { try { //logger.Info(typeof(ZTDataPullService), "开始服务"); if (DateTime.Now.Hour == 3 && DateTime.Now.Minute == 10) { bll.pageTaxpayerStage(); bll.findTaxpayerList(); bll.findOrganiseList(); } } catch (Exception ex) { logger.Error( typeof (ZTDataPullService), ex.Message); throw (ex); } } /// <summary> /// 拉取中台的数据 /// </summary> public void PullDataHandler() { try { logger.Info( typeof (ZTDataPullService), "开始服务" ); if ( false ) { bll.pageTaxpayerStage(); bll.findTaxpayerList(); bll.findOrganiseList(); } } catch (Exception ex) { throw (ex); } } /// <summary> /// 结束服务 /// </summary> protected override void OnStop() { logger.Info( typeof (ZTDataPullService), "结束服务" ); } } } |
2、注册服务,就是要将服务注册到注册表中(任务管理),在项目中添加“安装程序类”,会在项目中创建ProjectInstaller.cs类,在相应窗体设计器上生成了ServiceInstaller和ServiceProcessInstaller组件,其中ServiceInstaller属性中要绑定创建的服务名称一致与选择服务的启动方式,ServiceProcessInstaller中选择账户类型指定服务在计算机的系统帐户、本地或网络服务帐户或用户帐户下运行。
3、运行命令,对windows服务应用程序进行重新生成打包,在Debug或者Release文件可以找到相应的exe可执行文件,使用Powershell或者installutil.exe进行安装(执行命令行脚本的时候必须选择以管理员的方式运行),命令行脚本如下所示。
1 2 3 4 5 6 7 8 | // 安装命令行 %SystemRoot%\Microsoft.NET\Framework\v4.0.30319\installutil.exe %~dp0ZTDataPullService.exe Net Start ZTDataPullService sc config ZTDataPullService start= auto pause<br> //卸载命令 %SystemRoot%\Microsoft.NET\Framework\v4.0.30319\installutil.exe /u %~dp0ZTDataPullService.exe pause |
四、总结
Windows服务应用程序是微软提供对于在要长期运行后台程序的解决方式,通过结合Timer组件实现定时任务的效果,其无可视化界面,可以將日志消息记录到事件日志中,上述描述一个服务使用的Demo,具体内容参考微软文档,全面介绍方法,属性等内容。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?