关闭

C#开发系统服务时用的定时器组件(修正版)

标签: c#exceptionregexnullclassstring
2776人阅读 评论(30) 收藏 举报
分类:
// 相较上一版本改进
// 1. 修改Bug
//	当设置每月一次频率时,设置的Day日期如果为31,30,29,在有些年份的有些月份会抛出异常,因为有些月份是没有31天的,改正之后,
//	如果设置了31天,则只有有31天的月份会执行。
// 2. 修正一年中某天的日期较验功能。
// 3. 新增加循环模式
//	每个月最后一天执行一次。
// 4. 支持到秒的定时

using System;
using System.Text;
using System.Windows.Forms;
using UpSoft.Framework.CommonFunction.WinService;

namespace TestProject
{
	/// <summary>
	/// 测试服务
	/// </summary>
	public class TestServices : ServiceTimerControl
	{
		/// <summary>
		/// 服务代码
		/// </summary>
		protected override void StartService()
		{
			// 需要处理的服务代码
		}

		/// <summary>
		/// 时间配置策略名(可不重写。默认读配置文件中的default)
		/// </summary>
		public override string ConfigName { get { return "A"; } }
	}
}


要调用时,只需输入以下代码
new TestServices().Start();
//时间策略配置,可选择以下两种之一,配置文件,或是重写实现基类的获取时间策略配置
//1.代码重写
		/// <summary>
		/// 时间策略配置
		/// </summary>
		/// <returns></returns>
		protected override TimerConfig GetTimerConfig()
		{
			return new TimerConfig{ TimerMode=..., ...};
		}
//2.配置文件实现
<?xml version="1.0" encoding="utf-8"?>
<configuration>
	<configSections>
		<section name="ServiceTimerConfig" type="UpSoft.Framework.CommonFunction.WinService.ServiceTimerConfigManager,CommonFunction"></section>
	</configSections>
	<ServiceTimerConfig>
		<!--默认采用策略-->
		<Default>A</Default>
		<!--A配置项(全节点)-->
		<Config>
			<!--A策略-->
			<RefName>A</RefName>
			<TimerMode>Interval</TimerMode>
			<!--延迟开始处理(单位毫秒)可为空-->
			<Delay>10000</Delay>
			<!--文件生成时间间隔(单位毫秒,1800000=30分钟)-->
			<Interval>600000</Interval>
			<!--月份-->
			<MonthSeq></MonthSeq>
			<!--指定第几天的序号-->
			<DaySeq></DaySeq>
			<!--定时配置-->
			<Times>
				<!--一天之中需要执行任务的时间点-->
				<TimeValue>11:20:19</TimeValue>
				<TimeValue>10:10:43</TimeValue>
				<TimeValue>19:10:28</TimeValue>
			</Times>
		</Config>
		<!--B配置项(轮询策略)-->
		<Config>
			<!--B策略,每隔设置的时间执行一次-->
			<RefName>B</RefName>
			<TimerMode>Interval</TimerMode>
			<!--延迟开始处理(单位毫秒)-->
			<Delay>10000</Delay>
			<!--文件生成时间间隔(单位毫秒,1800000=30分钟)-->
			<Interval>600000</Interval>
		</Config>
		<!--C配置项(天设置)-->
		<Config>
			<!--C策略,每周4在配置的时间点上执行-->
			<RefName>C</RefName>
			<TimerMode>Week</TimerMode>
			<!--延迟开始处理(单位毫秒)-->
			<Delay>10000</Delay>
			<!--每周的星期四的以下时间执行-->
			<DaySeq>4</DaySeq>
			<!--定时配置-->
			<Times>
				<!--一天之中需要执行任务的时间点-->
				<TimeValue>11:20:19</TimeValue>
				<TimeValue>10:10:43</TimeValue>
				<TimeValue>19:10:28</TimeValue>
			</Times>
		</Config>
		<!--D配置项(月、天设置)-->
		<Config>
			<!--D策略,每年12月8号在配置的时间点上执行-->
			<RefName>D</RefName>
			<TimerMode>Month</TimerMode>
			<!--延迟开始处理(单位毫秒)-->
			<Delay>10000</Delay>
			<!--月份-->
			<MonthSeq>12</MonthSeq>
			<!--天数-->
			<DaySeq>8</DaySeq>
			<!--定时配置-->
			<Times>
				<!--一天之中需要执行任务的时间点-->
				<TimeValue>11:20:19</TimeValue>
				<TimeValue>10:10:43</TimeValue>
				<TimeValue>19:10:28</TimeValue>
			</Times>
		</Config>
	</ServiceTimerConfig>
</configuration>

// TimerMode的定义
	public enum TimerMode
	{
		///
		/// 轮询方式
		/// 
		Interval = 0,
		/// 
		/// 一个月中某个天数的指定时间
		/// 
		Month = 1,
		/// 
		/// 一周中的周几的指定时间
		/// 
		Week = 2,
		/// 
		/// 一天中的指定时间
		/// 
		Day = 3,
		/// 
		/// 一年中第几天的指定时间
		/// 
		Year = 4,
		/// 
		/// 一年中的指定日期的指定时间
		/// 
		Date = 5,
		/// 
		/// 每个月倒数第N天
		/// 
		LastDayOfMonth
		/// 
		/// 未设置
		/// 
		NoSet
	}

以下是组件的源代码

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Text.RegularExpressions;
using System.Threading;
using System.Xml;

namespace UpSoft.Framework.CommonFunction.WinService
{
	/// <summary>
	/// 服务定时器管理
	/// </summary>
	public abstract class ServiceTimerControl
	{
		#region 私有成员
		/// <summary>
		/// 定时器
		/// </summary>
		private Timer SysTimer { get; set; }
		/// <summary>
		/// 是否启用定时器
		/// </summary>
		private bool _EnabledTimer = true;
		/// <summary>
		/// 服务执行状态, 0-休眠, 1-运行
		/// </summary>
		private int _serviceStatus = 0;
		#endregion

		#region 公共属性
		/// <summary>
		/// 获取服务状态
		/// </summary>
		public int ServiceStatus { get { return _serviceStatus; } }

		/// <summary>
		/// 定时器配置
		/// </summary>
		public TimerConfig Config { get; set; }

		/// <summary>
		/// 时间计算类
		/// </summary>
		public TimerControl TimerControl { get; set; }

		/// <summary>
		/// 配置名称
		/// </summary>
		public virtual string ConfigName { get { return ( ServiceTimerConfigManager.ServiceConfig == null ? "" : ServiceTimerConfigManager.ServiceConfig.Default ); } }
		#endregion

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

			if ( SysTimer != null ) SysTimer.Change( Timeout.Infinite, Timeout.Infinite );
		}

		/// <summary>
		/// 开始服务
		/// </summary>
		public void Start()
		{
			try
			{
				_EnabledTimer = true;
				Config = this.GetTimerConfig();
				if ( Config.Delay == null )
					Config.Delay = new TimeSpan( 0 );

				SysTimer = new Timer( new TimerCallback( this.TimerProcess ), AppDomain.CurrentDomain, Config.Delay, this.Config.Interval );

				this.Logger( LogLevel.INFO, "服务启动成功!" );
			}
			catch ( Exception ex )
			{
				this.ServiceException( ex );
			}
		}

		/// <summary>
		/// 单次执行服务程序
		/// </summary>
		public void Process()
		{
			try
			{
				//开始处理服务
				this.StartService();
			}
			catch ( Exception ex ) { this.ServiceException( ex ); }	// 处理服务执行过程中出现的异常
		}

		/// <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
				{
					this.TimerControl = new TimerControl( this.Config );
					TimeIsUp = this.TimerControl.TimeIsUp;	// 获取是否到了执行服务程序的时间了
				}
				catch ( Exception ex )
				{
					// 读取配置出错且TimerControl对象已不存在,则再抛出异常
					// 如果上一次读取配置成功,那就就算这次的配置有问题,则也不会停止程序的运行,仍用上一次的数据做为参数
					if ( this.TimerControl == null ) throw ex;
				}
			}

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

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

					//开始处理服务
					this.StartService();
				}
			}
			catch ( Exception ex ) { this.ServiceException( ex ); }	// 处理服务执行过程中出现的异常
			finally
			{
				// 如果计时器不为空,则重新设置休眠的时间
				if ( SysTimer != null )
				{
					if ( this.Config.TimerMode == TimerMode.Interval )// 定时轮询设置
					{
						// 重新启用计时器
						SysTimer.Change( this.Config.Interval, this.Config.Interval );
					}
					else// 定时设置
					{
						// 用cft类计算下一次到期的时间
						TimeSpan Interval = this.TimerControl.GetNextTimeUp();
						// 重新启用计时器
						SysTimer.Change( Interval, Interval );
					}
				}
				_serviceStatus = 0;
			}
		}

		/// <summary>
		/// 开始服务
		/// </summary>
		protected abstract void StartService();

		/// <summary>
		/// 记录日志
		/// </summary>
		/// <param name="level">错误级别</param>
		/// <param name="msg"></param>
		protected virtual void Logger( LogLevel level, string msg ) { return; }

		/// <summary>
		/// 定时器初始化
		/// </summary>
		protected virtual TimerConfig GetTimerConfig()
		{
			var config = ServiceTimerConfigManager.ServiceConfig;
			if ( config != null && config.Config.Length > 0 )
			{
				// 如果没有配置则默认为第1个
				if ( String.IsNullOrEmpty( ConfigName ) )
					return config.Config[0];
				else// 返回配置项
					foreach ( var c in config.Config ) if ( String.Compare( c.RefName, ConfigName, true ) == 0 ) return c;
			}

			throw new Exception( "时间策略配置不正确!" );
		}

		/// <summary>
		/// 系统服务错误
		/// </summary>
		/// <param name="ex"></param>
		protected virtual void ServiceException( Exception ex ) { this.Logger( LogLevel.ERROR, "服务异常:" + ex.Message + " \r\n堆栈:" + ex.StackTrace ); }
	}

	#region 定时服务休眠计算类
	/// <summary>
	/// 文件生成时间配置
	/// </summary>
	public class TimerControl
	{
		#region 私有成员
		private TimerConfig Config { get; set; }
		#endregion

		#region 公共成员方法
		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="config">配置参数</param>
		/// </param>
		public TimerControl( TimerConfig config )
		{
			Config = config;
			if ( Config == null ) throw new Exception( "定时器时间配置异常!" );

			switch ( Config.TimerMode )
			{
				case TimerMode.Date:
					if ( Config.MonthSeq < 1 || Config.MonthSeq > 12 )
						throw new Exception( "定时器时间配置异常(月份取值只能是1~12)!" );
					var dt = new DateTime( 2012, Config.MonthSeq, 1 );	// 之所以选2012,是因为他是闰年,因此2月有29天。
					var lastDay = GetLastDayByMonth( dt );
					if ( Config.DaySeq < 1 || Config.DaySeq > lastDay )
						throw new Exception( "定时器时间配置异常(" + Config.MonthSeq + "月份的天数取值只能是1~" + lastDay + ")!" );
					break;
				case TimerMode.Day: break;
				case TimerMode.Month:
					if ( Config.DaySeq < 1 || Config.DaySeq > 31 )
						throw new Exception( "定时器时间配置异常(天数取值只能是1~31)!" );
					break;
				case TimerMode.Week:
					if ( Config.DaySeq < 0 || Config.DaySeq > 6 )
						throw new Exception( "定时器时间配置异常(星期取值只能是0~6)!" );
					break;
				case TimerMode.LastDayOfMonth:
					if ( Config.DaySeq != 0 )
					{// 如果等于0的话,表示是每个月的最后一天。
						if ( Config.DaySeq < 1 || Config.DaySeq > 28 )
							throw new Exception( "定时器时间配置异常(倒数的天数只能是1~28,即倒数的第1天,第2天。。。有些月份并没有29.30.31天,因此最大只允许倒数第28天)!" );
						Config.DaySeq -= 1;
					}
					break;
				case TimerMode.Year:
					if ( Config.DaySeq < 1 || Config.DaySeq > 366 )
						throw new Exception( "定时器时间配置异常(天数取值只能是1~366)!" );
					break;
			}
		}

		/// <summary>
		/// 判断时间是否到了
		/// </summary>
		/// <returns>true时间已经到了,false时间还未到</returns>
		public bool TimeIsUp
		{
			get
			{
				DateTime dt = DateTime.Now;
				if ( CheckTimeIsUp( dt.TimeOfDay ) )
				{
					switch ( Config.TimerMode )
					{
						case TimerMode.Day: return true;
						case TimerMode.Date: return dt.Month == Config.MonthSeq && dt.Day == Config.DaySeq;
						case TimerMode.Week: return ( ( int )dt.DayOfWeek ) == Config.DaySeq;
						case TimerMode.Month: return dt.Day == Config.DaySeq;
						case TimerMode.Year: return dt.DayOfYear == Config.DaySeq;
						case TimerMode.LastDayOfMonth: return dt.Day == ( GetLastDayByMonth( dt ) - Config.DaySeq );
						default: return false;
					}
				}
				else
					return false;
			}
		}

		/// <summary>
		/// 时间是否到了
		/// </summary>
		/// <returns></returns>
		private bool CheckTimeIsUp( TimeSpan time )
		{
			var tmp = new TimeSpan( time.Hours, time.Minutes, time.Seconds );
			if ( Config.Times == null )
				return ( tmp.Ticks == 0 );
			else
			{
				foreach ( var t in Config.Times )
				{
					if ( t == tmp ) return true;
				}
				return false;
			}
		}

		/// <summary>
		/// 从现在起到下次时间到还有多少时间
		/// </summary>
		/// <returns>时间间隔</returns>
		public TimeSpan GetNextTimeUp()
		{
			///目标时间
			DateTime _NextDateTime = this.GetNextDateTime();	// 保存下一次要执行的时间
			return _NextDateTime - DateTime.Now;
		}

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

					dt = new DateTime( dt.Year, dt.Month, dt.Day, time.Hours, time.Minutes, time.Seconds );
					#endregion
					break;
				case TimerMode.Month:
					#region 每月指定某天某时执行一次
					now = new DateTime( 1, 1, dt.Day, dt.Hour, dt.Minute, dt.Second );
					target = new DateTime( 1, 1, Config.DaySeq, time.Hours, time.Minutes, time.Seconds );	// 1月有31天,所以可以接受任何合法的Day值(因为在赋值时已判断1~31)
					if ( now.Ticks >= target.Ticks ) dt = dt.AddMonths( 1 );


					// 当前月份的指定天数执行过了,因此月份加上一个月,当月份加了一个月之后,很可能当前实现的Day值可能会变小(例:3月31号,加上一个月,则日期会变成,4月30号,而不会变成5月1号),
					// 因此需要判断指定的this.Day是不是比Day大(月份的Day变小的唯一原因是因为月份加了一个月之后,那个月并没有this.Day的天数),如果没有该this.Day的天数。则需要为该月份再加一个月。
					// 加一个月份,则那下个月一定可以大于等于this.Day, 看看每个月的天数就可以断定了,
					// 因为没有连着两个月的日期小于等于30的,只有连续两个月是31天。其它就是间隔的出现(this.Day最大只可能为31)
					// 如此之后,接下来的dt=new DateTime时不为因为dt.Month的月份,因没有this.Day天数而抛异常
					if ( Config.DaySeq > GetLastDayByMonth( dt ) ) dt = dt.AddMonths( 1 );	// 如此是为了确保dt.Month的月份一定有this.Day天(因此如果设置为每个月的31号执行的程序,就只会在1,3,5,7,8,10,12几个月份会执行)

					dt = new DateTime( dt.Year, dt.Month, Config.DaySeq, time.Hours, time.Minutes, time.Seconds );
					#endregion
					break;
				case TimerMode.LastDayOfMonth:
					#region 每个月倒数第N天的某时某刻执行一次
					var lastDaybymonth = GetLastDayByMonth( dt ) - Config.DaySeq;
					now = new DateTime( 1, 1, dt.Day, dt.Hour, dt.Minute, dt.Second );
					target = new DateTime( 1, 1, lastDaybymonth, time.Hours, time.Minutes, time.Seconds );	// 1月有31天,所以可以接受任何合法的Day值(因为在赋值时已判断1~31)
					if ( now.Ticks >= target.Ticks )
					{
						dt = dt.AddMonths( 1 );
						dt = new DateTime( dt.Year, dt.Month, GetLastDayByMonth( dt ) - Config.DaySeq, time.Hours, time.Minutes, time.Seconds );// 根据新月份求新月份的最后一天。
					}
					else
						dt = new DateTime( dt.Year, dt.Month, lastDaybymonth, time.Hours, time.Minutes, time.Seconds );
					#endregion
					break;
				case TimerMode.Week:
					#region 每星期指定星期某时执行一次
					int dow = ( int )dt.DayOfWeek;
					now = new DateTime( 1, 1, dow + 1, dt.Hour, dt.Minute, dt.Second );
					target = new DateTime( 1, 1, Config.DaySeq + 1, time.Hours, time.Minutes, time.Seconds );

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

					dt = new DateTime( dt.Year, dt.Month, dt.Day, time.Hours, time.Minutes, time.Seconds );
					#endregion
					break;
				case TimerMode.Date:
					#region 每年指定某月某日某时执行一次
					now = new DateTime( 4, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second );

					// 0004年闰年,可以支持2月29.因此选了0004, 这样就不会在构造Target时异常,
					// 因为比较的关键不在年。所以,只要Now和Target的年份一样就可以,设置成什么年份无所谓
					target = new DateTime( 4, Config.MonthSeq, Config.DaySeq, time.Hours, time.Minutes, time.Seconds );

					if ( now.Ticks >= target.Ticks ) dt = dt.AddYears( 1 );
					if ( Config.MonthSeq == 2 && Config.DaySeq == 29 )
					{
						// 因为闰年的最大间隔是8年,平时是4年一闰,可是0096年闰完之后,下一个闰年就是0104年,因此。。。
						for ( int i = 0; i < 8; i++ )
							if ( DateTime.IsLeapYear( dt.Year + i ) )
							{
								dt = dt.AddYears( i );
								break;
							}
					}

					dt = new DateTime( dt.Year, Config.MonthSeq, Config.DaySeq, time.Hours, time.Minutes, time.Seconds );
					#endregion
					break;
				case TimerMode.Year:
					#region 每年指定第N天某时执行一次
					now = new DateTime( 1, 1, 1, dt.Hour, dt.Minute, dt.Second );
					target = new DateTime( 1, 1, 1, time.Hours, time.Minutes, time.Seconds );
					if ( dt.DayOfYear > Config.DaySeq || dt.DayOfYear == Config.DaySeq && now.Ticks >= target.Ticks ) dt = dt.AddYears( 1 );
					dt = dt.AddDays( Config.DaySeq - dt.DayOfYear );

					dt = new DateTime( dt.Year, dt.Month, dt.Day, time.Hours, time.Minutes, time.Seconds );
					#endregion
					break;
				default:
					throw new Exception( "定时器时间配置异常!" );
			}

			return dt;
		}

		/// <summary>
		/// 获取指定日期所在月份的最后一天
		/// </summary>
		/// <param name="dt"></param>
		/// <returns></returns>
		private int GetLastDayByMonth( DateTime dt )
		{
			switch ( dt.Month )
			{
				case 4:
				case 6:
				case 9:
				case 11:
					return 30;
				case 2:
					return DateTime.IsLeapYear( dt.Year ) ? 29 : 28;
				default:
					return 31;
			}
		}

		/// <summary>
		/// 获取下一个时间点
		/// </summary>
		/// <returns></returns>
		private TimeSpan GetNextTimeConfig()
		{
			if ( Config.Times == null || Config.Times.Length == 0 )
				return new TimeSpan( 0 );
			else
			{
				var minData = TimeSpan.MaxValue;		// 最小时间
				var minExecData = TimeSpan.MaxValue;	// 大于当前时间的最小时间
				foreach ( var t in Config.Times )
				{
					if ( DateTime.Now.TimeOfDay < t && minExecData >= t )	// 找出比当前时间大的最小时间
						minExecData = t;
					if ( minData > t )	// 找出最小的一个时间,当前时间不参与运算
						minData = t;
				}

				if ( minExecData == TimeSpan.MaxValue )	// 如果找不到比当前时间大的最小时间,则选择最小时间返回
					return minData;
				else
					return minExecData;
			}
		}
		#endregion
	}
	#endregion

	#region 系统配置实体类&配置读取类
	/// <summary>
	/// 时间配置类
	/// </summary>
	public class ServiceTimerConfig
	{
		/// <summary>
		/// 默认配置
		/// </summary>
		public string Default { get; set; }
		/// <summary>
		/// 配置项
		/// </summary>
		public TimerConfig[] Config { get; set; }
	}
	/// <summary>
	/// 时间配置
	/// </summary>
	public class TimerConfig
	{
		/// <summary>
		/// 配置引用名
		/// </summary>
		public string RefName { get; set; }

		/// <summary>
		/// 时间模式
		/// timeMode取值如下:TimerMode.Month、TimerMode.Week、TimerMode.Week、TimerMode.Day、TimerMode.Date、TimerMode.Year
		/// </summary>
		public TimerMode TimerMode { get; set; }

		/// <summary>
		/// 指定某个时间算法的第几天,第1天就为1
		/// TimerMode=TimerMode.Month			时, 该DaySeq表示每个月中的第几天
		///	TimerMode=TimerMode.Week			时, 该DaySeq表示每个星期中的星期几(0-星期天,其它用1-6表示)
		///	TimerMode=TimerMode.Day				时, 该值不需要设置
		///	TimerMode=TimerMode.Date			时, 该DaySeq表示每个日期中的天数,如:8月12号,则DaySeq为12,MonthSeq为8
		///	TimerMode=TimerMode.LastDayOfMonth	时, 该DaySeq表示每个月倒数第几天
		///	TimerMode=TimerMode.Year			时, 该DaySeq表示每年中的第几天
		/// </summary>
		public int DaySeq { get; set; }

		/// <summary>
		/// 当指定一年中某个月的某个日期时有用到如:指定一年中8月12号,则这里的MonthSeq就应该为8
		/// </summary>
		public int MonthSeq { get; set; }

		/// <summary>
		/// 循环处理时间间隔(单位毫秒)
		/// </summary>
		public TimeSpan Interval { get; set; }

		/// <summary>
		/// 启动延迟时间(单位毫秒)
		/// </summary>
		public TimeSpan Delay { get; set; }

		/// <summary>
		/// 时间设置
		/// </summary>
		public TimeSpan[] Times { 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>
		/// 每个月倒数第N天
		/// </summary>
		LastDayOfMonth,
		/// <summary>
		/// 未设置
		/// </summary>
		NoSet
	}
	/// <summary>
	/// 读取配置数据
	/// </summary>
	public class ServiceTimerConfigManager : IConfigurationSectionHandler
	{
		private static Regex regEx = new Regex( @"^(?<h>[01]?\d|2[0-3])(?:[::](?<m>[0-5]\d?))?(?:[::](?<s>[0-5]\d?))?$", RegexOptions.Compiled | RegexOptions.IgnoreCase );

		/// <summary>
		/// 请求服务配置
		/// </summary>
		public static ServiceTimerConfig ServiceConfig { get; set; }
		/// <summary>
		/// 静态构造函数
		/// </summary>
		static ServiceTimerConfigManager()
		{
			ConfigurationManager.GetSection( "ServiceTimerConfig" );
		}
		/// <summary>
		/// 读取自定义配置节
		/// </summary>
		/// <param name="parent">父结点</param>
		/// <param name="configContext">配置上下文</param>
		/// <param name="section">配置区</param>
		/// <returns></returns>
		object IConfigurationSectionHandler.Create( object parent, object configContext, XmlNode section )
		{
			ServiceConfig = new ServiceTimerConfig();
			var config = new List<TimerConfig>();

			foreach ( XmlNode node in section.ChildNodes )
			{
				if ( node.NodeType == XmlNodeType.Element )
				{
					switch ( node.Name.ToLower() )
					{
						case "default":
							ServiceConfig.Default = node.InnerText;
							break; ;
						case "config":
							var tmp = new TimerConfig();
							SetTimerConfigValue( tmp, node );
							config.Add( tmp );
							break; ;
					}
				}
			}
			ServiceConfig.Config = config.ToArray();

			return ServiceConfig;
		}
		/// <summary>
		/// 设置定时器值
		/// </summary>
		/// <param name="Config"></param>
		/// <param name="node"></param>
		private void SetTimerConfigValue( TimerConfig Config, XmlNode node )
		{
			int tmp, h, m, s;
			long longTmp;
			var times = new List<TimeSpan>();

			foreach ( XmlNode xn in node.ChildNodes )
			{
				if ( xn.NodeType == XmlNodeType.Element )
				{
					switch ( xn.Name.ToLower() )
					{
						case "refname":
							Config.RefName = xn.InnerText;
							break;
						case "timermode":
							if ( xn.InnerText != null )
								Config.TimerMode = ( TimerMode )Enum.Parse( typeof( TimerMode ), xn.InnerText );
							break;
						case "delay":
							Int64.TryParse( xn.InnerText, out longTmp );
							Config.Delay = new TimeSpan( longTmp * 10 * 1000L );	// Delay配置值为毫秒
							break;
						case "interval":
							Int64.TryParse( xn.InnerText, out longTmp );		// Interval配置值为毫秒
							Config.Interval = new TimeSpan( longTmp * 10 * 1000L );
							break;
						case "monthseq":	// 月份
							Int32.TryParse( xn.InnerText, out tmp );
							Config.MonthSeq = tmp;
							break;
						case "dayseq":		// 指定第几天的序号
							Int32.TryParse( xn.InnerText, out tmp );
							Config.DaySeq = tmp;
							break;
						case "times":
							//还是用这个函数处理下一级的配置
							SetTimerConfigValue( Config, xn );	// 设置时间策略
							break;
						case "timevalue":
							var mc = regEx.Match( xn.InnerText );
							if ( !mc.Success ) throw new Exception( "时间配置不正确!" );
							Int32.TryParse( mc.Groups["h"].Value, out h );
							Int32.TryParse( mc.Groups["m"].Value, out m );
							Int32.TryParse( mc.Groups["s"].Value, out s );
							times.Add( new TimeSpan( h, m, s ) );
							break;
					}
				}
			}
			if ( times.Count != 0 )
				Config.Times = times.ToArray();
		}
	}
	#endregion
}




3
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:820558次
    • 积分:8911
    • 等级:
    • 排名:第2260名
    • 原创:116篇
    • 转载:210篇
    • 译文:3篇
    • 评论:112条
    个人简介
    本人家乡是宁德,现在福州工作. 如果您觉得这系列的文章对你有所帮助,

    欢迎打赏。

    支付宝打赏


    微信打赏
    文章分类
    最新评论