- // 相较上一版本改进
- // 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
- {
- ///<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
- }
以下是组件的源代码
- 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
- }