创建的Windows Service有时候是为了周期性的执行某一个计划任务,比如说我希望这个任务可以24小时执行一次,一般我们会设置一个Timer, 并且把Timer的TimeInterval设置为24小时,然后给Timer设置监听事件。
在这里我们创建一个Windows Service文件,MyService.cs, 类要继承自ServiceBase. 其中实现了一些OnStart, OnSotp方法等。
protected override void OnStart(string[] args) { this._timer = new System.Timers.Timer( 24 * 60 * 60 * 1000); this._timer.Enabled = true; this._timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed); this._timer.Start(); } private void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { //Add your schedule task here } protected override void OnStop() { //This method will be invoked when the windows service stops }
当你创建一个Windows Service的Project的时候,会有一个Program.cs文件,这个文件是整个程序的入口。在Program.cs文件中,Main方法为程序的入口,在这里注册你的继承自ServiceBase的MyService,然后就会调用其OnStart, OnStop等方法。
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
var servicesToRun = new ServiceBase[] { new MyService() };
ServiceBase.Run(servicesToRun);
}
}
关于Windows Service的调试,可以attach process的方式,但是这种方式比较费事,还有就是如果是schedule的任务的会,设置时间间隔为X分钟或者小时后,是必须先等这么一段时间才开始执行的。这里我们有一种非常直观的方式。即在MyService中设置一个Main方法,在Project Property中设置这个类为启动类,所以Debug New Instance的时候,就会以这个方法为入口进行,直接跳过所有的OnStart,OnStop等方法,那些方法是只有注册到Program.cs的ServiceBase中才起作用。
public partial class MyService : ServiceBase { static void Main(string[] args) { var service = new MyService(); service.JustStart(); } private void JustStart() { //这里就是你的Timer中的任务,把代码写到这里,可以立即执行,跟Timer就没有关系了。 } }在部署到电脑上的时候,也就是安装Service之前,要注意再把如果类改到Program.cs中。因为Windows Service启动的时候,也是再寻找Main方法入口,如果你这里还是MyService.cs中的Main方法,程序是会直接运行这里的代码的。而且,如果这里的操作比较费时的话,启动Windows Service的进度条会一直显示在启动过程中,因为只有Main方法运行完毕后,系统才认为这个service启动完成。有可能抛出异常,说Service因为问题没有在合理的事件内启动,是因为这个Main方法占用的时间太长了。
但是如果我们使用Program.cs里的Main方法启动的话,很快这个Main方法就会执行完成,因为只有两行代码,而Timer中的Task Code属于另外的线程,是不属于这个Main方法的。