这两天摸索了一下Windows服务调用quartz.net,在这里分享一下下,欢迎同学们给建设性的意见。

还是先大概介绍下quartz.net:

    你曾经需要应用执行一个任务吗?这个任务每天或每周星期二晚上1130,或许仅仅每个月的最后一天执行。一个自动执行而无须干预的任务在执行过程中如果发生一个严重错误,应用能够知到其执行失败并尝试重新执行吗?你和你的团队是用.NET编程吗?如果这些问题中任何一个你回答是,那么你应该使用Quartz.NET调度器。 Quartz.NET允许开发人员根据时间间隔(或天)来调度作业。它实现了作业和触发器的多对多关系,还能把多个作业与不同的触发器关联。整合了 Quartz.NET的应用程序可以重用来自不同事件的作业,还可以为一个事件组合多个作业.
   Quartz.NET是一个开源的作业调度框架,是OpenSymphony Quartz API.NET移植,它用C#写成,可用于winformasp.net应用中。它提供了巨大的灵活性而不牺牲简单性。你能够用它来为执行一个作业而创建简单的或复杂的调度。它有很多特征,如:数据库支持,集群,插件,支持cron-like表达式等等

以上介绍是从博客园张善友(http://www.cnblogs.com/shanyou/archive/2007/08/25/quartznettutorial.html)的博客摘抄来的,具体了解quartz.net还是到他的宝地学习,我这里只大概讲怎么应用。

这边博文还会用到log4net ,如果过不太了解log4net 可以到(http://blog.csdn.net/zhoufoxcn/article/details/2220533)来了解下。

这里对windows服务也是有一定要求的。

我在这里只讲对以上技术的应用,需要注意的地方我会重点提及,但不会对具体的原理做进一步解释。毕竟牵扯到的知识点不少,我只能笼统的讲解。

开始吧:

1,打开vs2010--新建项目--选择"Windows服务",我这里命名为"JobSchedulerTest". 创建好后首先映入我们眼帘的是Service1.cs[设计]视图,右键点设计视图选择"添加安装程序",如下图:

注释:(创建一个Windows服务,仅用InstallUtil程序去安装这个服务是不够的。你必须还要把一个服务安装程序添加到你的Windows服务当中,这样便于InstallUtil或是任何别的安装程序知道应用你服务的是怎样的配置设置)

2, 切换到刚被添加的ProjectInstaller的设计视图, 设置serviceInstaller1组件的属性: StartType = Automatic; 设置serviceProcessInstaller1组件的属性 Account = LocalSystem; 如下图:

3,JobSchedulerTest中添加Quartz.dll ,log4net.dll引用,在Services.cs文件中引用命名空间 Quartz;Quartz.Impl; log4net;

如下图,会报错,别急:

右键点击JobSchedulerTest项目,属性-目标框架 ,选择.net Framwork 4,如下图:

4,添加log4net.config配置文件,具体配置如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
</configSections>

<log4net>
<root>
<level value="ALL" />
</root>

<!-- job日志 -->
<logger name="Job.Status">
<level value="INFO" />
<appender-ref ref="Job.StatusAppender" />
</logger>
<appender name="Job.StatusAppender" type="log4net.Appender.RollingFileAppender,log4net" >
<param name="File" value="Logs\\Status\\" />
<param name="AppendToFile" value="true" />
<param name="RollingStyle" value="Date" />
<param name="DatePattern" value="yyyy-MM\\"Status-"yyyy-MM-dd".txt"" />
<param name="StaticLogFileName" value="false" />
<layout type="log4net.Layout.PatternLayout,log4net">
<param name="ConversionPattern" value="%d{yyy-MM-dd HH:mm:ss} %m%n" />
</layout>
</appender>
<!-- job日志 -->

<!-- 服务错误日志 -->
<logger name="Service.Error">
<level value="INFO" />
<appender-ref ref="Service.ErrorAppender" />
</logger>
<appender name="Service.ErrorAppender" type="log4net.Appender.RollingFileAppender,log4net" >
<param name="File" value="Logs\\Error\\" />
<param name="AppendToFile" value="true" />
<param name="RollingStyle" value="Date" />
<param name="DatePattern" value="yyyy-MM\\"ServiceError-"yyyy-MM-dd".txt"" />
<param name="StaticLogFileName" value="false" />
<layout type="log4net.Layout.PatternLayout,log4net">
<param name="ConversionPattern" value="%d{yyy-MM-dd HH:mm:ss} %m%n" />
</layout>
</appender>
<!-- 服务错误日志 -->
</log4net>
</configuration>

以上配置了记录日志的目录文件名(<param name="File" value="Logs\\Error\\" />)、txt命名样式(yyyy-MM\\"ServiceError-"yyyy-MM-dd".txt) 等信息。

具体介绍还是google吧?我对log4net认识也只局限于部分应用。

5,在解决方案中添加新项-选择"类库",我这里命名为JobLibrary,JobLibrary用来实现多个"作业"类。JobLibrary类库中添加Quartz.dll ,log4net.dll引用。

JobLibrary类库中添加一个类JobBase.cs,代码如下:

View Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using log4net;

namespace JobLibrary
{
public abstract class JobBase
{

/// <summary>
/// JOB状态日志
/// </summary>
protected internal static readonly ILog jobStatus = LogManager.GetLogger("Job.Status");

/// <summary>
/// 服务错误日志
/// </summary>
protected internal static readonly ILog serviceErrorLog = LogManager.GetLogger("Service.Error");
}
}

JobLibrary类库中再分别添加两个"作业"类test1.cs,test2.cs:

代码如下,因为只是个测试,所以我这里两个类方法几乎没多大区别:

test1.cs

View Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Quartz;
using Quartz.Impl;
using log4net;


namespace JobLibrary
{
public class test1 : JobBase, IJob
{
public void Execute(JobExecutionContext context)
{
jobStatus.Info(
"------------ test1 Start -----------");
try
{
jobtest1();
}
catch (Exception e)
{
serviceErrorLog.Info(String.Concat(
"test1:", e.StackTrace));
}
jobStatus.Info(
"------------ test1 Complete -----------");
jobStatus.Info(
"◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆");
}

//这里添加你的作业方法
public void jobtest1()
{
//我这里只是个测试 给日志问价写入字符串
jobStatus.Info(" weeksetting test1!");
}
}
}

test2.cs

View Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Quartz;
using Quartz.Impl;
using log4net;

namespace JobLibrary
{
public class test2 : JobBase, IJob
{
public void Execute(JobExecutionContext context)
{
jobStatus.Info(
"------------ test2 Start -----------");
try
{
jobtest2();
}
catch (Exception e)
{
serviceErrorLog.Info(String.Concat(
"test2:", e.StackTrace));
}
jobStatus.Info(
"------------ test1 Complete -----------");
jobStatus.Info(
"◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆");
}

//这里添加你的作业方法2
public void jobtest2()
{
//我这里只是个测试 给日志问价写入字符串
jobStatus.Info(" weeksetting test2!");
}
}
}

6,在JobSchedulerTest中引用JobLibrary
回到JobSchedulerTest中,添加配置文件JobScheduler.config,配置信息如下:

View Code
<?xml version="1.0" encoding="utf-8"?>
<JobScheduler>
<Job Description="作业1">
<DllName>JobLibrary.dll</DllName>
<Trigger name="test1" group="test1Group" type="CronTrigger" expression="0 0/2 * * * ?" />
<JobDetail job="test1" group="test1Group" jobtype="JobLibrary.test1" />
</Job>
<Job Description="作业2">
<DllName>JobLibrary.dll</DllName>
<Trigger name="test2" group="test2Group" type="CronTrigger" expression="0 0/5 * * * ?" />
<JobDetail job="test2" group="test2Group" jobtype="JobLibrary.test2" />
</Job>
</JobScheduler>
<!--
Cron Expressions——Cron 表达式

Cron表达式被用来配置CronTrigger实例。Cron表达式是一个由7个子表达式组成的字符串。每个子表达式都描述了一个单独的日程细节。这些子表达式用空格分隔,分别表示:

1. Seconds 秒

2. Minutes 分钟

3. Hours 小时

4. Day-of-Month 月中的天

5. Month 月

6. Day-of-Week 周中的天

7. Year (optional field) 年(可选的域)

一个cron表达式的例子字符串为
"0 0 12 ? * WED",这表示“每周三的中午12:00”。

单个子表达式可以包含范围或者列表。例如:前面例子中的周中的天这个域(这里是
"WED")可以被替换为"MON-FRI", "MON, WED, FRI"或者甚至"MON-WED,SAT"

通配符(
'*')可以被用来表示域中“每个”可能的值。因此在"Month"域中的*表示每个月,而在Day-Of-Week域中的*则表示“周中的每一天”。

所有的域中的值都有特定的合法范围,这些值的合法范围相当明显,例如:秒和分域的合法值为0到59,小时的合法范围是0到23,Day
-of-Month中值得合法凡范围是0到31,
但是需要注意不同的月份中的天数不同。月份的合法值是0到11。或者用字符串JAN,FEB MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV 及DEC来表示。
Days
-of-Week可以用1到7来表示(1=星期日)或者用字符串SUN, MON, TUE, WED, THU, FRI 和SAT来表示.

'/'字符用来表示值的增量,例如, 如果分钟域中放入'0/15',它表示“每隔15分钟,从0开始”,如果在份中域中使用'3/20',则表示“小时中每隔20分钟,
从第3分钟开始”或者另外相同的形式就是
'3,23,43'

'?'字符可以用在day-of-month及day-of-week域中,它用来表示“没有指定值”。这对于需要指定一个或者两个域的值而不需要对其他域进行设置来说相当有用。

'L'字符可以在day-of-month及day-of-week中使用,这个字符是"last"的简写,但是在两个域中的意义不同。例如,在day-of-month域中的"L"表示这个月的最后一天,
即,一月的31日,非闰年的二月的28日。如果它用在day
-of-week中,则表示"7"或者"SAT"。但是如果在day-of-week域中,这个字符跟在别的值后面,
则表示
"当月的最后的周XXX"。例如:"6L" 或者 "FRIL"都表示本月的最后一个周五。当使用'L'选项时,最重要的是不要指定列表或者值范围,否则会导致混乱。

'W' 字符用来指定距离给定日最接近的周几(在day-of-week域中指定)。例如:如果你为day-of-month域指定为"15W",则表示“距离月中15号最近的周几”。

'#'表示表示月中的第几个周几。例如:day-of-week域中的"6#3" 或者 "FRI#3"表示“月中第三个周五”。

下面是一些表达式以及它们的含义。

Example Cron Expressions ——Cron表达式的例子

CronTrigger

例1 – 一个简单的每隔5分钟触发一次的表达式

"0 0/5 * * * ?" CronTrigger

例2 – 在每分钟的10秒后每隔5分钟触发一次的表达式(例如.
10:00:10 am, 10:05:10等.)。

"10 0/5 * * * ?" CronTrigger

例3 – 在每个周三和周五的10:
30113012:30触发的表达式。

"0 30 10-13 ? * WED,FRI" CronTrigger

例4 – 在每个月的5号,20号的8点和10点之间每隔半个小时触发一次且不包括10点,只是8:
309:00和9:30的表达式。
"0 0/30 8-9 5,20 * ?" 注意,对于单独触发器来说,有些日程需求可能过于复杂而不能用表达式表述,例如:9:00到10:00之间每隔5分钟触发一次,
下午1:00到10点每隔20分钟触发一次。这个解决方案就是创建两个触发器,两个触发器都运行相同的任务。
-->

对于上面的理解要看看quartz的教程。

7.将log4net.config和JobScheduler.config配置文件复制到JobSchedulerTest.exe 服务应用程序所在的目录下。我的目录如下(D:\JobSchedulerTest\JobSchedulerTest\bin\Debug)
生成解决方案。

8,注册windows服务:

cmd打开命令行工具:

如果你系统是C盘,一般命令应该如下:

C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe  "你的windows服务路径"

我的win7系统装在F盘所以命令如下:

F:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe  D:\JobSchedulerTest\JobSchedulerTest\bin\Debug\JobSchedulerTest.exe

反注册如下:

F:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe  /u D:\JobSchedulerTest\JobSchedulerTest\bin\Debug\JobSchedulerTest.exe

这样注册就完了。

9,打开服务:

运行 下输入services.msc打开服务管理。如图:

或者 计算机-管理-服务和应用程序-服务 。刷新。可以查看到service1.如下图:

启动serivce1.

10 回到windows服务 应用程序所在目录,我的为:D:\JobSchedulerTest\JobSchedulerTest\bin\Debug\
你会发现多了个文件夹logs,logs里面还包括Error和Status文件夹。打开Status文件夹发现今天的日志文件夹,再打开发现今天的日志文件Status-2011-08-09.txt
上面的文件配置来自步骤4 。如果你了解log4net那就一目了然了。 在Status-2011-08-09.txt日志文件中,test1比test2出现的次数多? 这是因为在JobScheduler.config

的配置中 test1作业2分钟调用一次,test2作业5分钟调用一次。(expression="0 0/2 * * * ?" ) 这个学习quartz了,呵呵

大体就这样 ,多提宝贵意见,我是菜鸟很多地方还不懂。

作者: 程序员蛋子 发表于 2011-08-09 16:38 原文链接

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"