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

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

下面是应用实例

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

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 = ; /// 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, , 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 = ,
/// <summary>
/// 一个月中某个天数的指定时间
/// </summary>
Month = ,
/// <summary>
/// 一周中的周几的指定时间
/// </summary>
Week = ,
/// <summary>
/// 一天中的指定时间
/// </summary>
Day = ,
/// <summary>
/// 一年中第几天的指定时间
/// </summary>
Year = ,
/// <summary>
/// 一年中的指定日期的指定时间
/// </summary>
Date = ,
/// <summary>
/// 未设置
/// </summary>
NoSet
}
/// <summary>
/// 服务处理方法
/// </summary>
public enum ServiceStatus
{
/// <summary>
/// 休眠中
/// </summary>
Sleep = ,
/// <summary>
/// 服务在执行过程中
/// </summary>
Running =
}
#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 = ;
#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( , , , dt.Hour, dt.Minute, );
target = new DateTime( , , , this.Hour, this.Minute, );
if ( now.Ticks >= target.Ticks ) dt = dt.AddDays( 1.0 ); //如果当前时间小于指定时刻,则不需要加天 dt = new DateTime( dt.Year, dt.Month, dt.Day, this.Hour, this.Minute, );
#endregion
break;
case TimerMode.Month:
#region 每月指定某天某时执行一次
now = new DateTime( , , dt.Day, dt.Hour, dt.Minute, );
target = new DateTime( , , this.Day, this.Hour, this.Minute, );
if ( now.Ticks >= target.Ticks ) dt = dt.AddMonths( ); dt = new DateTime( dt.Year, dt.Month, this.Day, this.Hour, this.Minute, );
#endregion
break;
case TimerMode.Week:
#region 每星期指定星期某时执行一次
int dow = ( int )dt.DayOfWeek;
now = new DateTime( , , dow + , dt.Hour, dt.Minute, );
target = new DateTime( , , this.Day + , this.Hour, this.Minute, ); if ( now.Ticks >= target.Ticks )
dt = dt.AddDays( this.Day - dow + );
else
dt = dt.AddDays( this.Day - dow ); dt = new DateTime( dt.Year, dt.Month, dt.Day, this.Hour, this.Minute, );
#endregion
break;
case TimerMode.Date:
#region 每年指定某月某日某时执行一次
now = new DateTime( , dt.Month, dt.Day, dt.Hour, dt.Minute, );
target = new DateTime( , this.Month, this.Day, this.Hour, this.Minute, );
if ( now.Ticks >= target.Ticks ) dt = dt.AddYears( ); dt = new DateTime( dt.Year, this.Month, this.Day, this.Hour, this.Minute, );
#endregion
break;
case TimerMode.Year:
#region 每年指定第N天某时执行一次
now = new DateTime( , , , dt.Hour, dt.Minute, );
target = new DateTime( , , , this.Hour, this.Minute, );
if ( dt.DayOfYear > this.Day || dt.DayOfYear == this.Day && now.Ticks >= target.Ticks ) dt = dt.AddYears( );
dt = dt.AddDays( this.Day - dt.DayOfYear ); dt = new DateTime( dt.Year, dt.Month, dt.Day, this.Hour, this.Minute, );
#endregion
break;
default:
throw new Exception( "定时器时间配置异常!" );
} return dt;
}
#endregion
}
#endregion
}

C#开发系统服务时用的定时器组件的更多相关文章

  1. 【Android开发精要笔记】Android组件模型解析

    Android组件模型解析 Android中的Mashup 将应用切分成不同类别的组件,通过统一的定位模型和接口标准将他们整合在一起,来共同完成某项任务.在Android的Mashup模式下,每个组件 ...

  2. 前端开发:setTimeout与setInterval 定时器与异步循环数组

    前端开发:setTimeout与setInterval 定时器与异步循环数组 前言: 开通博客园三个月以来,随笔记录了工作中遇到的大大小小的难题,也看过无数篇令人启发的文章,我觉得这样的环境是极好的, ...

  3. Angular开发实践(四):组件之间的交互

    在Angular应用开发中,组件可以说是随处可见的.本篇文章将介绍几种常见的组件通讯场景,也就是让两个或多个组件之间交互的方法. 根据数据的传递方向,分为父组件向子组件传递.子组件向父组件传递及通过服 ...

  4. 实验三 CC2530平台上CC2530平台上定时器组件的

    实验三 CC2530平台上CC2530平台上定时器组件的TinyOS编程 实验目的: 加深和巩固学生对于TinyOS编程方法的理解和掌握 让学生初步掌握CC2530定时器的PWM功能,及其TinyOS ...

  5. SNF快速开发平台MVC-瀑布式分页组件

    1.   瀑布式分页 目前已经比较流行了,以往的这种点击分页已经不能满足广大网民的需求了.像百度图片等等,网站都有滚动滚轮直接分页的功能,这样体验也确实好了不少,所以我们也决定在我们的框架内进行集成此 ...

  6. 驱动开发:内核枚举DpcTimer定时器

    在笔者上一篇文章<驱动开发:内核枚举IoTimer定时器>中我们通过IoInitializeTimer这个API函数为跳板,向下扫描特征码获取到了IopTimerQueueHead也就是I ...

  7. JS-自制提速小工具:开发页面时需要按比例计算宽高值的快速计算器

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <meta name= ...

  8. MyEclipse使用总结——设置MyEclipse开发项目时使用的JDK

    安装好MyEclipse之后,在MyEclipse中开发项目时,默认使用的是MyEclipse是自带的JDK,如下图所示: 如果我们需要使用自己安装好的JDK,那么就需要在MyEclipse中重新设置 ...

  9. 设置MyEclipse开发项目时使用的JDK

    安装好MyEclipse之后,在MyEclipse中开发项目时,默认使用的是MyEclipse是自带的JDK,如下图所示: 如果我们需要使用自己安装好的JDK,那么就需要在MyEclipse中重新设置 ...

随机推荐

  1. QT笔记之VS2012 TCP传送文件

    注意:工程监理后,因为用到网路,所以要加入对应的库 服务器: .h #ifndef TCPFILE_H #define TCPFILE_H #include <QtWidgets/QWidget ...

  2. 蚁群算法简介(part3: 蚁群算法之更新信息素)

    信息素的局部更新策略   每只蚂蚁在构造出一条从起点到终点的路径后,蚁群算法还要求根据路径的总长度来更新这条路径所包含的每条边上信息素的浓度(在旅行商问题中每座城市是图中的一个节点,城市两两间有一条边 ...

  3. SQL-Server使用点滴(一)

    前言 SQL的语法比较简单,学起来相比界面UI控制要简单得多,但是SQL在企业级应用中又是如此的重要,以至于很多开发人员都把重点放在SQL上. SQL并没有面向对象的概念,最复杂的设计也不过是表值函数 ...

  4. 《与小卡特一起学Python》 Code5 for循环

    import time for i in range(10,0,-1): print i time.sleep(1) print "Blast off!" 以上代码循环意思为: 从 ...

  5. PNG的使用技巧

    Png是图像文件存储格式,在网页设计中已经不是一个陌生的名词,在前端开发中经常使用到它,如常用CSS 雪碧图.而Png的使用不仅仅如此,Png有多少种格式,有哪些特点,PC端中常用的Png格式是哪些, ...

  6. SQLServer的数据存储结构01 文件与文件组

    在SQLServer中,每当新建一个数据库时,则会有一组相应的SQLServer文件被创建,这些单独的SQLServer文件构成的总体称为文件组. 一个数据库对应着一个文件组,在这个文件组里,会包括三 ...

  7. 无法删除对象 '产品',因为该对象正由一个 FOREIGN KEY 约束引用。

    在删除northwindcs表时,发生报错,消息 3726,级别 16,状态 1,第 2 行,无法删除对象 '产品',因为该对象正由一个 FOREIGN KEY 约束引用.此时判断是因为有其他表的外键 ...

  8. 如何在页面进入时就加载js

    页面一打开就执行JS的代码! onLoadwindow.onLoad=function(){}window.onload=function(){ } 补充:window.onload和doucumen ...

  9. 【转】Centos升级Python 2.7.12并安装pip、ipython

    Centos系统一般默认就安装有Python2.6.6版本,不少软件需要2.7以上的,通过包管理工具安装不了最新的版本,通过源码编译可以方便安装指定版本,只需要把下面版本的数字换成你想要的版本号. 1 ...

  10. java 的 sqlHelper,改改之后也适用于不使用 EF 的 C# 项目,包含查询和建表。

    这个类用来拼接 sql. package com.ly.orm; public class Query { protected Query(String v) { sql = v; } public ...