您的位置:首页 > 编程语言 > C#

C#开发系统服务时用的定时器组件

2010-08-27 13:47 330 查看
写服务时,都需要为定时器写不少的代码,感觉很麻烦,今天把这些代码封装一下,希望能简化一下这方面的工作,把精力都集中在功能上

本定时器组件,每次只启动一个服务实例进行处理,而不会同时多次执行服务代码。



下面是应用实例

从组件类派生一个子类,可以看到,需要写的代码很少



using System;   
using System.Collections.Generic;   
using System.IO;   
using System.Text.RegularExpressions;   
using System.Threading;
  
namespace BlueVision.SaYuan.WinService   
{   
    public class TestService : ServiceTimerContorl   
    {   
        protected override void StartService()   
        {   
            //需要做的事情的代码   
        }   
  
        protected override ServiceTimeConfig GetTimerConfig()   
        {   
            ServiceTimeConfig config = new ServiceTimeConfig();   
  
            // 如果该枚举是选择 Interval ,则表示,上述的 StartService 方法,将隔 config.ChkInterval 毫秒执行一次   
            config.TimerMode = TimerMode.Interval;   
            config.ChkInterval = 100000;   
  
  
            /// StartTime值为:   
            ///    
            /// TimerMode=TimerMode.Month   "09|04:30"  -表示每月9号的凌晨4点30分   
            /// TimerMode=TimerMode.Week     "0|04:30"  -表示每星期天的4点30分   
            /// TimerMode=TimerMode.Week     "6|04:00"  -表示每星期6的4点30分   
            /// TimerMode=TimerMode.Day       "|04:00"  -表示每天的4点00分   
            /// TimerMode=TimerMode.Date "08-10|04:00"  -表示每年8月10号的4点00分执行一次   
            /// TimerMode=TimerMode.Year   "246|04"     -表示每年第246天的4点00分执行一次(可以不填写分钟默认为00)   
  
            //如果是这样设置 则表示,每天的凌晨 4 点 00 执行一次   
            config.TimerMode = TimerMode.Day;   
            config.StartTime = "|04";   
  
            //如果是这样设置 则表示,每个星期的星期四那天的凌晨 6 点 35 执行一次   
            config.TimerMode = TimerMode.Week;   
            config.StartTime = "4|06:35";   
  
            //如果是这样设置 则表示,每个星期的星期天那天的凌晨 6 点 00 执行一次   
            config.TimerMode = TimerMode.Week;   
            config.StartTime = "0|06";   
  
            //如果是这样设置 则表示,每个月的9号凌晨 6 点 28 执行一次   
            config.TimerMode = TimerMode.Month;   
            config.StartTime = "09|06:28";   
  
            //如果是这样设置 则表示,每年8月10号的4点00分执行一次   
            config.TimerMode = TimerMode.Date;   
            config.StartTime = "08-10|04:00";   
  
            //如果是这样设置 则表示,每年第246天的4点27分执行一次   
            config.TimerMode = TimerMode.Year;   
            config.StartTime = "246|04:27";   
  
            return config;   
        }   
        /// <summary>   
        /// 当服务出错时,处理   
        /// </summary>   
        /// <param name="ex"></param>   
        protected override void  ServiceException(Exception ex)   
        {   
             //可以不实现   
        }   
    }   
}   
  
  
//要执行代码,以下这样就可以了
TestService testService = new TestService();   
testService.Start();






以下是组件的源代码

using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading;

namespace BlueVision.SaYuan.WinService
{
	/// <summary>
	/// 服务定时器管理
	/// </summary>
	public abstract class ServiceTimerControl
	{
		#region 私有成员
		/// <summary>
		/// 定时器
		/// </summary>
		private Timer SysTimer { get; set; }
		/// <summary>
		/// 是否启用定时器
		/// </summary>
		private bool _EnabledTimer = true;
		/// <summary>
		/// 服务执行状态
		/// </summary>
		private ServiceStatus _serviceStatus = ServiceStatus.Sleep;
		/// <summary>
		/// 时间计算类
		/// </summary>
		private TimerControl _timerControl = null;
		/// <summary>
		/// 定时器配置
		/// </summary>
		ServiceTimeConfig Config;
		#endregion

		#region 公共属性
		/// <summary>
		/// 获取服务状态
		/// </summary>
		public ServiceStatus ServiceStatus { get { return _serviceStatus; } }
		/// <summary>
		/// 计时模式
		/// </summary>
		public TimerMode TimerMode
		{
			get
			{
				if ( Config == null ) Config = this.GetTimerConfig();

				return Config.TimerMode;
			}
		}
		/// <summary>
		/// 计时配置
		/// </summary>
		public string StartTime { get { return ( Config == null ) ? "" : Config.StartTime; } }
		/// <summary>
		/// 时间计算类
		/// </summary>
		public TimerControl TimerControl
		{
			get
			{
				if ( Config == null )
					Config = this.GetTimerConfig();
				if ( _timerControl == null )
					_timerControl = new TimerControl( this.Config.StartTime, this.Config.TimerMode );

				return _timerControl;
			}
		}
		#endregion

		/// <summary>
		/// 停止
		/// </summary>
		public void Stop()
		{
			_EnabledTimer = false;

			SysTimer.Change( Timeout.Infinite, Timeout.Infinite );
		}
		/// <summary>
		/// 开始服务
		/// </summary>
		public void Start()
		{
			_EnabledTimer = true;
			Config = this.GetTimerConfig();

			SysTimer = new Timer( new TimerCallback( this.TimerProcess ), AppDomain.CurrentDomain, 0, this.Config.ChkInterval );
		}
		/// <summary>
		/// 处理间隔服务
		/// </summary>
		/// <param name="sender"></param>
		private void TimerProcess( object sender )
		{
			if ( !_EnabledTimer ) return;

			bool TimeIsUp = true;
			if ( this.Config.TimerMode != TimerMode.Interval )
			{
				// 如果定时方式不是定时轮询的话,就构造TimerControl类,该类用来计算每次执行完程序后
				// 到下次执行服务时需要休眠的时间
				try
				{
					_timerControl = new TimerControl( this.Config.StartTime, this.Config.TimerMode );
					TimeIsUp = _timerControl.TimeIsUp;	// 获取是否到了执行服务程序的时间了
				}
				catch ( Exception ex )
				{
					// 读取配置出错且TimerControl对象已不存在,则再抛出异常
					// 如果上一次读取配置成功,那就就算这次的配置有问题,则也不会停止程序的运行,仍用上一次的数据做为参数
					if ( _timerControl == null ) throw ex;
				}
			}

			try
			{
				if ( TimeIsUp )// 时间到了可以执行程序了
				{
					// 服务运行了
					_serviceStatus = ServiceStatus.Running;

					// 设置计时器,在无穷时间后再启用(实际上就是永远不启动计时器了--停止计时器计时)
					SysTimer.Change( Timeout.Infinite, this.Config.ChkInterval );

					//开始处理服务
					this.StartService();
				}
			}
			catch ( Exception ex ) { this.ServiceException( ex ); }	// 处理服务执行过程中出现的异常
			finally
			{
				// 如果计时器不为空,则重新设置休眠的时间
				if ( SysTimer != null )
				{
					if ( this.Config.TimerMode == TimerMode.Interval )// 定时轮询设置
					{
						// 重新启用计时器
						SysTimer.Change( this.Config.ChkInterval, this.Config.ChkInterval );
					}
					else// 定时设置
					{
						// 用cft类计算下一次到期的时间
						TimeSpan Interval = _timerControl.GetNextTimeUp();
						// 重新启用计时器
						SysTimer.Change( Interval, Interval );
					}
				}
				_serviceStatus = ServiceStatus.Sleep;
			}
		}
		/// <summary>
		/// 开始服务
		/// </summary>
		protected abstract void StartService();
		/// <summary>
		/// 定时器初始化
		/// </summary>
		/// <param name="TimerMode"></param>
		/// <param name="StartTime"></param>
		/// <param name="ChkInterval"></param>
		protected abstract ServiceTimeConfig GetTimerConfig();
		/// <summary>
		/// 系统服务错误
		/// </summary>
		/// <param name="ex"></param>
		protected virtual void ServiceException( Exception ex ) { return; }
	}

	#region 定时器相关实体类
	/// <summary>
	/// 服务定时器配置
	/// </summary>
	public class ServiceTimeConfig
	{
		/// <summary>
		/// 轮询目录时间间隔(单位:毫秒)
		/// </summary>
		public int ChkInterval { get; set; }
		/// <summary>
		/// StartTime值为:
		/// 
		/// TimerMode=TimerMode.Month	"09|04:30"	-表示每月9号的凌晨4点30分
		///	TimerMode=TimerMode.Week	 "0|04:30"	-表示每星期天的4点30分
		/// TimerMode=TimerMode.Week	 "6|04:00"	-表示每星期6的4点30分
		///	TimerMode=TimerMode.Day		  "|04:00"	-表示每天的4点00分
		///	TimerMode=TimerMode.Date "08-10|04:00"	-表示每年8月10号的4点00分执行一次
		///	TimerMode=TimerMode.Year   "246|04"		-表示每年第246天的4点00分执行一次(可以不填写分钟默认为00)
		/// </summary>
		public string StartTime { get; set; }
		/// <summary>
		/// 服务器定时处理模型
		/// </summary>
		public TimerMode TimerMode { get; set; }
	}
	/// <summary>
	/// 服务处理方法
	/// </summary>
	public enum TimerMode
	{
		/// <summary>
		/// 轮询方式
		/// </summary>
		Interval = 0,
		/// <summary>
		/// 一个月中某个天数的指定时间
		/// </summary>
		Month = 1,
		/// <summary>
		/// 一周中的周几的指定时间
		/// </summary>
		Week = 2,
		/// <summary>
		/// 一天中的指定时间
		/// </summary>
		Day = 3,
		/// <summary>
		/// 一年中第几天的指定时间
		/// </summary>
		Year = 4,
		/// <summary>
		/// 一年中的指定日期的指定时间
		/// </summary>
		Date = 5,
		/// <summary>
		/// 未设置
		/// </summary>
		NoSet
	}
	/// <summary>
	/// 服务处理方法
	/// </summary>
	public enum ServiceStatus
	{
		/// <summary>
		/// 休眠中
		/// </summary>
		Sleep = 0,
		/// <summary>
		/// 服务在执行过程中
		/// </summary>
		Running = 1
	}
	#endregion

	#region 定时服务休眠时间计算类
	/// <summary>
	/// 定时服务休眠时间计算类
	/// </summary>
	public class TimerControl
	{
		#region 私有成员
		/// <summary>
		/// 间隔单位
		/// </summary>
		private TimerMode type;
		/// <summary>
		/// 月份
		/// </summary>
		private int Month;
		/// <summary>
		/// 天
		/// </summary>
		private int Day;
		/// <summary>
		/// 小时
		/// </summary>
		private int Hour;
		/// <summary>
		/// 分钟
		/// </summary>
		private int Minute = 0;
		#endregion

		#region 公共成员方法
		/// <summary>
		/// StartTime值为:
		/// 
		/// TimerMode=TimerMode.Month	"09|04:30"	-表示每月9号的凌晨4点30分
		///	TimerMode=TimerMode.Week	 "0|04:30"	-表示每星期天的4点30分
		/// TimerMode=TimerMode.Week	 "6|04:00"	-表示每星期6的4点30分
		///	TimerMode=TimerMode.Day		  "|04:00"	-表示每天的4点00分
		///	TimerMode=TimerMode.Date "08-10|04:00"	-表示每年8月10号的4点00分执行一次
		///	TimerMode=TimerMode.Year   "246|04"		-表示每年第246天的4点00分执行一次(可以不填写分钟默认为00)
		/// </summary>
		/// <param name="StartTime"></param>
		/// <param name="timeMode"></param>
		public TimerControl( string StartTime, TimerMode timeMode )
		{
			//Regex regEx = new Regex( @"(?<Type>[MWDY])(?<Days>/d+)?/|(?<Hour>/d+):?(?<Minute>[0-5]/d?)?", RegexOptions.Compiled | RegexOptions.IgnoreCase );
			Regex regEx = new Regex( @"^(?:(?<Month>[0]?/d|1[0-2])-)?(?<Days>/d{1,3})?/|(?<Hour>[01]?/d|2[0-3])(?::(?<Minute>[0-5]/d?))?$", RegexOptions.Compiled | RegexOptions.IgnoreCase );

			this.type = timeMode;

			Match m = regEx.Match( StartTime );
			if ( m.Success )
			{
				if ( String.IsNullOrEmpty( m.Groups["Month"].Value ) && this.type == TimerMode.Date )
					throw new Exception( "定时器时间配置异常!" );

				if ( !String.IsNullOrEmpty( m.Groups["Month"].Value ) )
					this.Month = Convert.ToInt32( m.Groups["Month"].Value );

				if ( !String.IsNullOrEmpty( m.Groups["Days"].Value ) )
					this.Day = Convert.ToInt32( m.Groups["Days"].Value );

				this.Hour = Convert.ToInt32( m.Groups["Hour"].Value );

				if ( !String.IsNullOrEmpty( m.Groups["Minute"].Value ) )
					this.Minute = Convert.ToInt32( m.Groups["Minute"].Value );
			}
			else
				throw new Exception( "定时器时间配置异常!" );
		}
		/// <summary>
		/// 判断时间是否到了
		/// </summary>
		/// <returns></returns>
		public bool TimeIsUp
		{
			get
			{
				DateTime dt = DateTime.Now;
				switch ( type )
				{
					case TimerMode.Day:
						return ( dt.Hour == this.Hour && dt.Minute == this.Minute );
					case TimerMode.Month:
						return ( dt.Day == this.Day && dt.Hour == this.Hour && dt.Minute == this.Minute );
					case TimerMode.Week:
						return ( ( ( int )dt.DayOfWeek ) == this.Day && dt.Hour == this.Hour && dt.Minute == this.Minute );
					case TimerMode.Date:
						return ( dt.Month == this.Month && dt.Day == this.Day && dt.Hour == this.Hour && dt.Minute == this.Minute );
					case TimerMode.Year:
						return ( dt.DayOfYear == this.Day && dt.Hour == this.Hour && dt.Minute == this.Minute );
				}
				return false;
			}
		}
		/// <summary>
		/// 从现在起到下次时间到还有多少时间
		/// </summary>
		/// <returns></returns>
		public TimeSpan GetNextTimeUp()
		{
			///目标时间
			DateTime _NextDateTime = this.GetNextDateTime();	// 保存下一次要执行的时间
			TimeSpan NextCrtFileTime = _NextDateTime - DateTime.Now;

			if ( ( int )NextCrtFileTime.TotalMilliseconds > int.MaxValue )	// 如果要休眠的时间间隔超过int类型可以表示的毫秒时,先休眠到int.MaxValue,然后再次休眠
				NextCrtFileTime = new TimeSpan( int.MaxValue );

			return NextCrtFileTime;
		}
		/// <summary>
		/// 获取下一次指定配置的时间是多少
		/// </summary>
		/// <returns></returns>
		public DateTime GetNextDateTime()
		{
			DateTime dt = DateTime.Now;
			DateTime now, target;
			switch ( this.type )
			{
				case TimerMode.Day:
					#region 每天指定某时执行一次
					now = new DateTime( 1, 1, 1, dt.Hour, dt.Minute, 0 );
					target = new DateTime( 1, 1, 1, this.Hour, this.Minute, 0 );
					if ( now.Ticks >= target.Ticks ) dt = dt.AddDays( 1.0 );	//如果当前时间小于指定时刻,则不需要加天

					dt = new DateTime( dt.Year, dt.Month, dt.Day, this.Hour, this.Minute, 0 );
					#endregion
					break;
				case TimerMode.Month:
					#region 每月指定某天某时执行一次
					now = new DateTime( 1, 1, dt.Day, dt.Hour, dt.Minute, 0 );
					target = new DateTime( 1, 1, this.Day, this.Hour, this.Minute, 0 );
					if ( now.Ticks >= target.Ticks ) dt = dt.AddMonths( 1 );

					dt = new DateTime( dt.Year, dt.Month, this.Day, this.Hour, this.Minute, 0 );
					#endregion
					break;
				case TimerMode.Week:
					#region 每星期指定星期某时执行一次
					int dow = ( int )dt.DayOfWeek;
					now = new DateTime( 1, 1, dow + 1, dt.Hour, dt.Minute, 0 );
					target = new DateTime( 1, 1, this.Day + 1, this.Hour, this.Minute, 0 );

					if ( now.Ticks >= target.Ticks )
						dt = dt.AddDays( this.Day - dow + 7 );
					else
						dt = dt.AddDays( this.Day - dow );

					dt = new DateTime( dt.Year, dt.Month, dt.Day, this.Hour, this.Minute, 0 );
					#endregion
					break;
				case TimerMode.Date:
					#region 每年指定某月某日某时执行一次
					now = new DateTime( 1, dt.Month, dt.Day, dt.Hour, dt.Minute, 0 );
					target = new DateTime( 1, this.Month, this.Day, this.Hour, this.Minute, 0 );
					if ( now.Ticks >= target.Ticks ) dt = dt.AddYears( 1 );

					dt = new DateTime( dt.Year, this.Month, this.Day, this.Hour, this.Minute, 0 );
					#endregion
					break;
				case TimerMode.Year:
					#region 每年指定第N天某时执行一次
					now = new DateTime( 1, 1, 1, dt.Hour, dt.Minute, 0 );
					target = new DateTime( 1, 1, 1, this.Hour, this.Minute, 0 );
					if ( dt.DayOfYear > this.Day || dt.DayOfYear == this.Day && now.Ticks >= target.Ticks ) dt = dt.AddYears( 1 );
					dt = dt.AddDays( this.Day - dt.DayOfYear );

					dt = new DateTime( dt.Year, dt.Month, dt.Day, this.Hour, this.Minute, 0 );
					#endregion
					break;
				default:
					throw new Exception( "定时器时间配置异常!" );
			}

			return dt;
		}
		#endregion
	}
	#endregion
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: