タイマージョブを作成する機会があったので、メモがてら記録しておきます。
はじめる
- Visual Studio 2010 で、” 空のSharePointプロジェクト” から始めます。
- デバッグの設定は、サンドボックスではなく、”ファーム” にします。
- 特定のサイトに対するジョブを作成する場合は、デバッグの設定でそのサイトを指定します。
- Features の下にフィーチャを追加します。
- タイトル、説明、スコープを設定します。スコープについては、後述。
- そのフィーチャを右クリックして、イベントレシーバを追加します。イベントレシーバについては、後述。
- パッケージの名前、タイトル、および説明を必要に応じて設定します。
- パッケージにフィーチャを追加します。(というか、既定で追加されています)
- プロジェクトにクラスを追加します。このクラスがジョブの本体になります。後述。
フィーチャのスコープ
フィーチャのスコープは “Farm” または “Site” にしますが、この設定によって、ジョブの Execute() メソッドの中での this.Parent の内容や、FeatureActivated( SPFeatureReceiverProperties properties ) の properties 引数の内容が変わってきます。要するに、コンテキストが変わります。したがって、ジョブの処理内容が特定のサイト コレクションに関係することであれば Site を、ファーム全体に対する処理 (サイトコレクションをまたぐような処理) であれば Farm を選びます。
イベント レシーバ
アクティブ時
フィーチャがアクティブになったときに、次のようにジョブを登録するようにします。
public override void FeatureActivated( SPFeatureReceiverProperties properties ) {
SPWebService service = properties.Feature.Parent as SPWebService;
SPFarm farm = service.Farm;
SPService timer = null;
timer = getSPTimer( farm );
if( timer != null ) {
foreach( SPJobDefinition job in timer.JobDefinitions ) {
if( job.Name == List_JOB_NAME ) {
job.Delete(); // Delete all living jobs.
}
}
} else {
throw new Exception("Could not get SPTimerV4 Service.");
}
// install the job
Job one = null;
try {
one = new Job( List_JOB_NAME, timer, null, SPJobLockType.Job );
} catch {
throw new Exception( "Installing the job failed." );
}
try {
SPMinuteSchedule schedule = new SPMinuteSchedule();
schedule.BeginSecond = 0;
schedule.EndSecond = 59;
#if DEBUG
schedule.Interval = 1;
#else
schedule.Interval = 15;
#endif
one.Schedule = schedule;
one.Update();
} catch {
throw new Exception( "Scheduling the job failed." );
}
}
非アクティブ時
フィーチャが非アクティブになったときに、次のようにジョブを削除するようにします。
public override void FeatureDeactivating( SPFeatureReceiverProperties properties ) {
SPWebService service = properties.Feature.Parent as SPWebService;
SPFarm farm = service.Farm;
SPService timer = null;
timer = getSPTimer( farm );
if( timer != null ) {
foreach( SPJobDefinition job in timer.JobDefinitions ) {
if( job.Name == List_JOB_NAME ) {
job.Delete();
}
}
} else {
throw new Exception( "Could not get SPTimerV4 Service." );
}
}
SPJobDefinition
追加したクラスは、SPJobDefinitionクラスを継承するようにします。
public class Job : SPJobDefinition {
private const String CoreName = "My Time Job Title";
public Job()
: base() {
}
public Job( string jobName, SPService service, SPServer server, SPJobLockType targetType )
: base( jobName, service, server, targetType ) {
this.Title = CoreName;
}
public Job( string jobName, SPWebApplication webApplication )
: base( jobName, webApplication, null, SPJobLockType.ContentDatabase ) {
this.Title = CoreName;
}
public override string Description {
get {
return "This time job is doing something on entire site collections.";
}
}
public override string DisplayName {
get {
return CoreName;
}
}
public override void Execute( Guid contentDbId ) {
}
}
この、Execute メソッドに処理を記述します。
その他
配置
一般的な SharePoint プロジェクト同様、Visual Studioの [配置] コマンドでソリューションを配置できますが、配置後にタイマーを再起動する必要があります。
net stop SPTimerV4
net start SPTimerV4
デバッグ
タイマージョブに限りませんが、デバッグのためにトレースログを出すように設定しておくと便利です。
次のようなクラスを追加し、コード中で diag.WriteTrace( 1, cat, TraceSeverity.Verbose, "{0} == {1}", a, b ); といったようにして書き出します。
class Diagnostics : SPDiagnosticsServiceBase {
public enum CategoryId {
None = 0,
Deployment = 100,
Provisioning = 200,
CustomAction = 300,
Rendering = 400,
WebPart = 500
}
private static string DiagnosticsAreaName = "MyTimerJob";
public Diagnostics()
: base() {
}
public Diagnostics( String name, SPFarm parent )
: base( name, parent ) {
}
protected override IEnumerable ProvideAreas() {
List categories = new List();
foreach( string catName in Enum.GetNames( typeof( CategoryId ) ) ) {
uint catId = (uint)(int)Enum.Parse( typeof( CategoryId ), catName );
categories.Add( new SPDiagnosticsCategory( catName, TraceSeverity.Verbose, EventSeverity.Error, 0, catId ) );
}
yield return new SPDiagnosticsArea( DiagnosticsAreaName, categories );
}
public static Diagnostics Local {
get {
return SPDiagnosticsServiceBase.GetLocal();
}
}
public SPDiagnosticsCategory this[CategoryId id] {
get {
return Areas[DiagnosticsAreaName].Categories[id.ToString()];
}
}
}
Dispose
トレースログをきちんと確認するようにします。SPSite や SPWeb などをきちんと Dispose していないと、”An SPRequest object was not disposed before the end of this thread.” といったようなメッセージが記録されます。ある意味、便利です。
Comments