イベント ハンドラを使う際の注意点

みなさん。こんにちは kenmori です。

 

本日は、皆様に SharePoint が用意しているイベント ハンドラについて、特に SPItemEventReceiver についてのご紹介とその注意点についてお伝えいたします。

 

イベント ハンドラって何?

イベントハンドラとは簡単に申しますと、何かのタイミングに任意の処理を実行させるカスタマイズになります。

発生する前と後に実行でき、発生前の処理では何と抑止することもできてしまいます。

 

イメージとしては例えば・・・、ご飯を食べた後のイベントで、歯を磨く処理をプログラミングしておきます。

こうすることで、虫歯を防ぐことができて、健康的ですね。

 

その他の例

食べる前に飲む (何か聞いたことがある・・・)

食べる前にやめとく (ダイエットのため)

 

本当に食べる動作にイベント ハンドラがつけられるとすれば、それはロボットの開発の話みたいですので、SharePoint のお話をいたします。

 

SharePoint ではアイテムを追加、更新、削除するタイミングでイベント ハンドラがよく使われています。

補足

イベント ハンドラを実施するためには、まず Visual Studio が必要です (2005 以降)。

Edition は何でも大丈夫です。VSeWSS は非サポートツールですが便利です。

 

タイトル : Windows SharePoint Services 3.0 ツール: Visual Studio 2008 Extensions Version 1.2

アドレス : https://www.microsoft.com/downloads/details.aspx?displaylang=ja&FamilyID=7bf65b28-06e2-4e87-9bad-086e32185e68

 

タイトル : Windows SharePoint Services 3.0 ツール: Visual Studio 2005 Extensions Version 1.1

アドレス : https://www.microsoft.com/downloads/details.aspx?familyid=3E1DCCCD-1CCA-433A-BB4D-97B96BF7AB63&displaylang=ja

 

概要手順

 

VSeWSS をインストールした開発環境にて、イベント ハンドラの開発を実施するには以下のような手順で開始します。

 

1. SharePoint の "空のプロジェクト" を作成します。

2. ソリューション エクスプローラより、プロジェクト ファイルを右クリックし [追加] - [新しい項目] をクリックします。

3. テンプレートより "イベント レシーバ" が選べます。

 

clip_image002

 

 

イベント ハンドラを使用するシナリオ

今回は前述いたしましたとおり、アイテムに対するイベント (SPItemEventReceiver) についてのご説明になりますが、SharePoint でこういったカスタマイズが使われるシナリオをいくつかご紹介させていただきます。

 

例えば、アイテムを追加、編集、削除した際にイベントが呼べますのでこんなことができます。

 

・ユーザーの入力文字列を検証する

 複数のフィールド間に入力されたデータの組み合わせを検証する場合には良い方法です。

  (例 "2009" 年 "2" 月 "31" 日は不正な日付です! etc.)

 

 個々のフィールドに対しては、カスタムフィールドの方がベターです。

 しかし、カスタムフィールドの入力検証を実装するのに敷居が高いと感じる方にはオススメです。

 

・列に対して自動的に値を生成してセットする

 参照列でも実装できない複雑な数式も実現できます。

 

・作成したアイテムにデフォルトの権限を指定する

 登録したアイテムが、最初は自分のみ見えるなどの運用が可能です。

 フォルダ権限を編集すると性能問題があるので、SP2 適用後をオススメします。

 

・アイテムの削除を禁止する

 

イベント ハンドラに不向きなシナリオ

イベントハンドラに不向きなシナリオもあります。

・何日間 (または何時間) も継続するような処理を実装する場合

 イベントハンドラの実行中は常にメモリを確保した状況になりますので、何件も起動してしまうと大量なメモリが消費されてしまい、メモリが枯渇してしまうことにもなりかねません。即時完了する処理のみ実装し、長期に渡るビジネスロジックなどを実施する場合は、カスタム ワークフローをご検討ください。

 

・何度も実行されると困る処理

 例えば、メールを送信するなどの処理を実装していると、何通も重複したメールを受信してしまう可能性があります。

 詳細は注意点に記載いたします。

 

イベント ハンドラを使う際の注意点

さて、本題に入ります。イベントハンドラを使う際の注意点ですが、影響度の高いものを集めて記載しております。

開発の際にはご参考にしてください。

 

1. 非同期の -ed イベントで更新後のデータを扱う場合は要注意

 

-ing は同期イベントですが、-ed は非同期イベントと MSDN に記載があります。非同期とはどういうことかと申しますと、別のスレッドで動作することとなります。

 

タイトル : SPItemEventReceiver メソッド (Microsoft.SharePoint)

アドレス : https://msdn.microsoft.com/ja-jp/library/microsoft.sharepoint.spitemeventreceiver_methods.aspx

 

これの何が要注意かと申しますと、データが更新される前にイベントが呼ばれていることもあるのです。

このイベントが発生するタイミングはデータベースにデータが更新されるタイミングよりも若干早いため、アイテムが存在しない状況で ItemAdded イベントが呼ばれたり、ItemUpdated イベントでSPWeb から新たに SPListItem を取得した値が更新前の値だったりといったことがあります。(かなり稀です。)

 

同期された値はこれらのプロパティで取得するようにしてください。これらの値を使用すれば、更新前の処理を取得するようなことを避けることができます。

・properties.BeforeProperites

・properties.AfterProperties

 

しかしながら、properties.ListItem やそのプロパティ情報を参照したり、SPSite や SPWeb を別途生成して、 SPListItem にアクセスする際は同期がとれていない可能性があることを想定してプログラムを実装ください。特に、マルチ CPU 環境ではお気をつけください。

 

タイトル : SPItemEventProperties.BeforeProperties プロパティ (Microsoft.SharePoint)

アドレス : https://msdn.microsoft.com/ja-jp/library/microsoft.sharepoint.spitemeventproperties.beforeproperties.aspx

 

タイトル : SPItemEventProperties.AfterProperties プロパティ (Microsoft.SharePoint)

アドレス : https://msdn.microsoft.com/ja-jp/library/microsoft.sharepoint.spitemeventproperties.afterproperties.aspx

 

- 対処策

 どうしても同期されていないプロパティを使用したい場合は、更新されるのを待つ方法があります。

残念ながら、更新が完全が終わっていることを知るためのプロパティ値などはないようですので、Thread.Sleep メソッドを使用してスレッドを待機させながら、処理をリトライするのが唯一の方法と考えられます。

 

2. イベント ハンドラで無限ループに陥る

 

アイテムが更新された後のイベントで、さらにアイテムを更新した場合どうなるか・・・。もちろん、イベントがまた発生します。

これがきっかけとなり ItemUpdated イベントの無限ループとなってしまいます。

 

先ほど申し上げたとおり ItemUpdated イベントは別スレッドで動作するので、無限ループに陥っていても画面上のパフォーマンスに直接影響せず、気付かないことが多いのです。十分に動作をご確認ください。

 

- 対処策

properties.DisableEventFiring メソッドを呼び出して、イベント ハンドラの処理で再帰的にイベントを発生させないようにしましょう。

 

タイトル : SPEventReceiverBase.DisableEventFiring メソッド (Microsoft.SharePoint)

アドレス : https://msdn.microsoft.com/ja-jp/library/microsoft.sharepoint.speventreceiverbase.disableeventfiring.aspx

 

元に戻すには、EnableEventFiring メソッドを呼び出します。

 

タイトル : SPEventReceiverBase.EnableEventFiring メソッド (Microsoft.SharePoint)

アドレス : https://msdn.microsoft.com/ja-jp/library/microsoft.sharepoint.speventreceiverbase.enableeventfiring.aspx

 

3. ホスト プロセスはアイテムを操作したプロセスです。

 

イベントハンドラはアセンブリとして SharePoint サーバーに展開しますが、実行されるホスト プロセスは、ワーカープロセス (w3wp.exe) であるとは限りません。

例えば、お客様が作成したコンソールアプリケーションから SharePoint のアイテムを追加、編集など実施した場合は、コンソール アプリケーションがホストプロセスとなります。

 

特にファイルの相対パスなど、ホストプロセスが何かによって影響する処理を記載する際はご注意ください。

また Visual Studio より [デバッグ] - [プロセスにアタッチ] にてイベント ハンドラをデバッグする際には、アイテム追加、更新、削除を実施するホストプロセスが何であるかを確認の上、実施ください。

clip_image004

 

 

4. エクスプローラ ビューを使用する際は要注意です。

 

ドキュメントライブラリなどにイベント ハンドラを関連づける時は要注意です。

 

clip_image006

 

エクスプローラビューを使ってファイルをアップロードすると、サーバー側で通常にファイルを保存するのと異なる動作になります。

例えば、エクスプローラビューを使用してファイルをアップロードすると、遅延書き込みが発生します。

 

- 遅延書き込みの簡単なご説明

遅延書き込みを簡単にご説明しますと、例えばリムーバブル ディスクやネットワーク プレースへのファイル書き込みなど、処理時間がかかるファイル I/O 処理を非同期的に実行することにより、画面操作やファイル I/O 処理を最適化するための動作となります。

ファイル アップロードの動作においては、まずサーバー側でアップロード対象のファイル (この時点では 0 KB) を作成します。その後、サーバーに転送されてくるファイルのデータを一度メモリにバッファさせ、システム上適切なタイミングにて適時書き込み処理を実施していくことで、書き込み効率を最適化しております。

 

MSDN には、エクスプローラ ビューに関する内容として以下のような記述がございます

新しいアイテムを追加するときは、ItemAdded イベントのみ発生します。ただし、エクスプローラ ビューが使用される場合は、ItemAdded および ItemUpdated イベントが両方とも発生します。その際、ItemUpdated イベントは常に ItemAdded イベントの後で発生します。

 

タイトル : SPItemEventReceiver.ItemUpdated メソッド (Microsoft.SharePoint)

アドレス : https://msdn.microsoft.com/ja-jp/library/microsoft.sharepoint.spitemeventreceiver.itemupdated.aspx

 

イベントは書き込まれた回数呼び出されます。

例えば、遅延書き込みによってバックグラウンドのスレッドが 1 つのファイルを保存するにあたり 4 回書き込みを実施した場合、1 回の ItemAdded イベントと 3 回の ItemUpdated イベントが発生する動作となります。

この結果、イベントハンドラにてメールを送信するなどの処理を実施した場合は、不要なメールが飛び交うことが考えられます。

SharePoint 側は更新されたエクスプローラ ビューより更新されてくるイベントを検知して処理を実施するだけですので、残念ながら SharePoint としてこの複数回発生する更新を変更することはできません。

 

- 対処策

 メール送信の処理はできればワークフローで実装してください。

 

 もちろんワークフローも内部的にはイベントで起動されますので、2 回発生することも考えられます。

 その場合は、一番最後に待機処理を入れて、処理が瞬時に終わらないようにしましょう。

 ワークフローは多重起動できませんので処理が複数回実施されるのを避けることができます。

(2010 年 1 月 6 日 追記)

イベント ハンドラの注意点のうち、エクスプローラ ビューを使用する際の注意点をピックアップしたブログを作成しております。

より詳細な情報が必要な場合はこちらをご覧ください。

(https://blogs.technet.com/sharepoint_support/archive/2010/01/06/3303951.aspx)

5 アイテムのチェック イン時の動作について

 

チェックインが発生した際は、アイテムの更新イベントも発生します。

つまり、アイテムを更新してチェックインを実施すると、2 回更新イベントが発生することになります。

 

純粋にチェックインだけを取得するのであれば、ItemCheckingIn、ItemCheckedIn イベントというものもございます。

タイトル : SPItemEventReceiver.ItemCheckingIn メソッド (Microsoft.SharePoint)

アドレス : https://msdn.microsoft.com/ja-jp/library/microsoft.sharepoint.spitemeventreceiver.itemcheckingin.aspx

タイトル : SPItemEventReceiver.ItemCheckedIn メソッド (Microsoft.SharePoint)

アドレス : https://msdn.microsoft.com/ja-jp/library/microsoft.sharepoint.spitemeventreceiver.itemcheckedin.aspx

まとめ

 

イベントハンドラと聞くと、何でも簡単に実装できてしまうような錯覚に陥ります。

しかしながら、上述のような処理のタイミングに依存した現象が発生することも考えられますので、お客様に機能をご提案する方には事前にプロトタイプ版などを作成し、事前に動作を十分に検証いただいた上で実施ください。

もしもトラブルにぶつかった場合・・・、そんな場合には私たちが可能な限り対応させていただきますので、お問い合わせください。

参考情報

 

参考情報を記載いたします。

 

タイトル : イベントの基礎

アドレス : https://msdn.microsoft.com/ja-jp/library/ms442323.aspx

 

タイトル : 基本的なイベント ハンドラを作成する

アドレス : https://msdn.microsoft.com/ja-jp/library/ms437502.aspx

 

タイトル : OFFICE SPACE SharePoint 2007 のイベント
アドレス : https://msdn.microsoft.com/ja-jp/magazine/cc163318.aspx

 

肌寒くなってきましたね。

冒頭の話ではないですが、イベント ハンドラではお体は守れませんので、ご自身でお体にお気をつけて食べ過ぎ、飲みすぎにご注意ください。

 

以上、kenmori でした。