前一段时间为了满足公司的要求,需要使用Timer的特性来进行开发。当时碰到这个需求的时候,首先想到的,就是写一个控制台程序放在服务器上跟着MOSS2007一起跑算了,可是后来想了一下,似乎在管理中心见过计时器的特性。随即打开了“计时器作业定义”,研究了半天也没有头绪,接着一头栽进SDK里搜寻了半天,发现了这个SPJobDefinition类似乎有点意思,不过需要使用SPFeatureReceiver这个类来进行部署,也就是说,制作一个可以部署的计时器,需要分成两个部分来设计:
首先,编写计时器程序,也就是继承于SPJobDefinition的类,我写的叫做EventCheckTimer。
其次,编写部署这个计时器所需要的安装器,也就是继承SPFeatureReceiver的类,我这里叫做EventCheckTimerInstaller
然后就很清楚了,使用这个Installer将EventCheckTimer部署到服务器上,部署的方式,是将feature.xml、mainifest.xml、强命名密钥、以及这两个类生成的dll文件打包成wsp格式的文件(其实就是cab文件),你也许会用到这个wsp部署的模板:wsp模板。
好的,我们引入程序:
这一个类是Timer Job的主类,系统主要是调用里边的Execute方法,这个方法的参数targetInstanceId(内容数据库ID)并不需要你来传递,而是系统在合适的时间在调用的时候自动传递的,你可以把它看作几乎被我们写烂的Main函数:)
using
System;
using
Microsoft.SharePoint;
using
Microsoft.SharePoint.Administration;
namespace
MyCompany.Management.Employees
{
///
<summary>
///
这一个类是计时器的主工作类,系统会按照在Installer中
///
设定的schedule定期调用此类中的Execute方法
///
</summary>
public
class
EventCheckTimer : SPJobDefinition
{
public
EventCheckTimer() :
base
() { }
///
<summary>
///
初始化EventCheckTimer
///
更多的构造函数请参看SDK
///
</summary>
///
<param name="_timername">
计时器的名称
</param>
///
<param name="_wp">
Web应用程序名称
</param>
public
EventCheckTimer(
string
_timername, SPWebApplication _wp)
:
base
(_timername, _wp,
null
, SPJobLockType.ContentDatabase)
{
this
.Title
=
"
合同到期提醒器0.04
"
;
}
///
<summary>
///
此方法由系统调用,contentDbId也由系统传递
///
</summary>
///
<param name="_contentdbid">
内容数据库的id
</param>
public
override
void
Execute(Guid targetInstanceId)
{
SPWebApplication webApplication
=
this
.Parent
as
SPWebApplication;
SPContentDatabase contentDb
=
webApplication.ContentDatabases[targetInstanceId];
DateTime dt;
//
遍历当前员工库中的员工,审查所有可能的提醒事件
foreach
(SPListItem li
in
contentDb.Sites[
0
].AllWebs[
"
Employees
"
].Lists[
"
员工库
"
].Items)
{
if
(li[
"
合同止时间
"
]
!=
null
)
{
dt
=
Convert.ToDateTime(li[
"
合同止时间
"
]);
TimeSpan ts
=
(dt.Date
-
DateTime.Today.Date);
//
如果合同止时间小于当前时间,这种情况一般只发生在服务崩溃的时候
if
(dt.Date
<
DateTime.Now.Date)
{
SPListItem si
=
contentDb.Sites[
0
].AllWebs[
"
Employees
"
].Lists[
"
任务
"
].Items.Add();
si[
"
标题
"
]
=
String.Format(
"
{0}的合同已经到期!
"
, li[
"
员工姓名
"
]);
si[
"
截止日期
"
]
=
DateTime.Now.AddDays(
7
);
si.Update();
}
else
if
(ts.Days
<=
30
)
//
如果距离现在有30天的时间,那么发出提醒
{
SPListItem si
=
contentDb.Sites[
0
].AllWebs[
"
Employees
"
].Lists[
"
任务
"
].Items.Add();
si[
"
截止日期
"
]
=
DateTime.Now.AddDays(
7
);
si[
"
标题
"
]
=
String.Format(
"
{0}的合同将于{1}天后到期,日期:{2}
"
, li[
"
员工姓名
"
], (dt.Date
-
DateTime.Now.Date), li[
"
合同止时间
"
]);
si.Update();
}
}
}
}
}
}
在设定完TimerJob的时候,就可以编写安装器了,下边是代码:其实可以照抄的,不过要注意在FeatureActivated中改成你要部署的计时器的对象,还有就是计时器的计时周期,需要改成你自己需要的。这里的BeginSecond和EndSecond指的是计时器满足触发条件的时候,在一分钟内的那一段时间内执行,比如我这就是可以在0~59秒内执行。其他计时周期类似。
using
System;
using
Microsoft.SharePoint;
using
Microsoft.SharePoint.Administration;
namespace
MyCompany.Management.Employees
{
///
<summary>
///
这一个类的作用主要是安装某一个功能到站点上
///
被安装的对象的类必须是从SPJobDefinition继承
///
过来的
///
</summary>
class
EventCheckTimerInstaller : SPFeatureReceiver
{
const
string
MY_TASK
=
"
EventCheckTimer
"
;
///
<summary>
///
在功能被安装以后被调用
///
</summary>
public
override
void
FeatureInstalled(SPFeatureReceiverProperties properties)
{
}
///
<summary>
///
在功能被卸载的时候被调用
///
</summary>
public
override
void
FeatureUninstalling(SPFeatureReceiverProperties properties)
{
}
///
<summary>
///
在功能被激活的时候被调用
///
</summary>
public
override
void
FeatureActivated(SPFeatureReceiverProperties properties)
{
//
取得当前站点的作用域
SPSite site
=
properties.Feature.Parent
as
SPSite;
//
确保在安装此功能之前系统不被调用
foreach
(SPJobDefinition job
in
site.WebApplication.JobDefinitions)
{
if
(job.Name
==
MY_TASK)
job.Delete();
}
//
安装TimerJob
EventCheckTimer timer
=
new
EventCheckTimer(MY_TASK, site.WebApplication);
//
设置记时器的工作计划表,在这里是每日启动一次,运行时间00:00-05:00,更多的Timer请参看SDK,最小是只执行一次,最长是一天
//
SPDailySchedule schedule = new SPDailySchedule();
//
schedule.BeginHour = 0;
//
schedule.EndHour = 5;
SPMinuteSchedule schedule
=
new
SPMinuteSchedule();
schedule.BeginSecond
=
0
;
schedule.EndSecond
=
59
;
schedule.Interval
=
1
;
timer.Schedule
=
schedule;
timer.Update();
}
///
<summary>
///
在功能被冻结的时候被调用
///
</summary>
public
override
void
FeatureDeactivating(SPFeatureReceiverProperties properties)
{
SPSite site
=
properties.Feature.Parent
as
SPSite;
//
删除这个功能
foreach
(SPJobDefinition job
in
site.WebApplication.JobDefinitions)
{
if
(job.Name
==
MY_TASK)
job.Delete();
}
}
}
}
如果你用了wsp安装包,那么部署激活的顺序是这样的
stsadm -o addsolution -filename yourwspfile.wsp
stsadm -o deploysolution -name yourwspfile.wsp -immediate -allowgacdeployment -force
stsadm.exe -o execadmsvcjobs '这一段是立即执行部署操作
net stop "Windows SharePoint Services Timer" '重启计时器服务,
net start "Windows SharePoint Services Timer"
resetiis
在解决方案管理里部署你的解决方案
在网站集功能里打开这个功能,就OK了。
如果你要卸载Timer,就比较麻烦~~~
首先需要在网站集功能里关闭功能,然后执行
stsadm -o deletesolution -name ZTEsoft.Management.Employees.EventCheckTimer.wsp -override
千万记着最后要重启Windows SharePoint Services Timer刷新服务,否则网站集还是会继续执行Timer服务的。
这点也许对于调试不是很爽,其实因为你写的程序是周期性的执行,所以你可以先模拟TimerJob的执行环境在控制台程序里执行一下,确保万事OK了,再放在Execute函数里,用Installer包装一下安装就可以了。
如果你只是测试,那么测试完成后一定要记得关掉网站集功能,否则也许在将来的某天,你的数据库会被同样的信息塞满的:)