Dynamics CRM 2011 プラグインのベストプラクティス

みなさん、こんにちは。

Microsoft Dynamics 製品の売りの 1 つに、柔軟な拡張性があります。Dynamics CRM の
場合には、コーディングなしで拡張が実現できるカスタマイズやワークフロー、ダイアログや
グラフツールなどの機能の他に、C# や VB.NET、JScript や Silverlight 開発を利用した拡張も
サポートされています。

今回はそれらの中でも利用頻度の高い、プラグインのベストプラクティスに関して情報を提供します。

プラグイン開発の注意点

プラグインが原因でパフォーマンスが低下する主な理由をいくつか紹介します。

データ取得に関する問題

プラグイン内では、様々なデータが処理に必要となります。例えば作成されたばかりの
レコードの GUID や、関連レコードのデータなどです。しかしデータ読み取りの部分で
パフォーマンスに問題をかかえるプラグインを良く見かけます。

- InputParameters、OutputParameters を利用する
プラグイン内では Context が利用でき、Context には InputParameter と OutputParameter
が提供されます。処理に必要な情報がこちらに存在しないかまずは確認してください。

- Image を利用する
InputParameter と OutputParameter はメイン操作に必須の情報のみ格納していますが、
Image を利用することで、付加情報をコンテキストの一部としてプラグインに渡すことが
可能です。例えばレコードを更新する場合には、更新される列の情報しか InputParameter
には含まれませんが、他の列の情報がプラグインで必要な場合、Image として取得できます。

- RetrieveMultiple には注意
複数のレコードから情報を得たい場合には、RetrieveMultiple メソッドを利用することに
なります。ただし、RetrieveMultiple を利用する場合には、必ず必要最小限の列のみを
指定することと、Condition を利用して、取得するレコード数も最小限にしてください。

SDK 内のサンプルでは new ColumnSet(true); がよく利用されていますが、本番では
利用しないように注意してください。RetrieveMultiple のパフォーマンスに関しては、
後日別の記事で紹介します。

組織サービスに関する問題

プラグイン内では組織サービスを利用した操作を行うことが多くなります。その場合、
以下の注意を守ってください。

- 組織サービスはコンテキストより取得する
プラグイン内で組織サービスを利用する場合は、必ずコンテキストよりサービスを
取得してください。

IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)); IOrganizationService service = factory.CreateOrganizationService(context.UserId);

コンテキストより取得した組織サービスはパフォーマンスが最適化されています。

- プラグイン内では同じ組織サービスを利用する
プラグイン内の一連の流れて、組織サービスを何度か利用する場合には、都度
組織サービスを生成せず、一番初めに生成した組織サービスを利用してください。

登録するステップの問題

プラグインは、Dynamics CRM サーバーが処理する様々なメッセージに対して登録できます。
しかし、プラグインを登録するということは、その分の処理が増えるということになりますので、
無駄な処理をさけるようにする必要があります。

- Execute にはプラグインを登録しない
他に手段がない場合を除いて、Execute にはプラグインの登録を行わず、Retrieve、 Update
等より詳細なメッセージに登録することを強くお勧めします。

- エンティティを指定する
登録するメッセージを絞る同時に、対象となるエンティティもかならず指定してください。
例えば特定のいくつかのエンティティに対して Update に対する処理を行いたい場合は、
それぞれのエンティティごとにステップを登録してください。そうすることで他のエンティティ
に対する Update 処理では、該当のプラグインが呼ばれなくなります。

- サービスを作成する前に分岐処理をする
プラグイン実行にあたり、コードの初めのほうに各種サービスに作成を行いますが、
サービス作成した結果、なにも処理をしない場合は無駄になるため、分岐処理は極力
前のほうで行い、無駄な処理が呼ばれないようにしてください。

‐ IPluginExecutionContext.Depth を利用する
プラグインが呼ばれた際に、それがループになっていないか確認するための手段として
IPluginExecutionContext.Depth があります。すでにループ対策として利用されていると
思いますが、無駄な実行を避けるためにも Depth をチェックしてください。

- Pre-Validation ステージの利用
メイン操作の前に処理を行うプラグインが、データのチェックなどを行うだけでレコードの
作成や更新を行わない場合には、メイン操作と同一トランザクションで処理を実行する
必要はありません。この場合は Pre-Validation ステージを利用してください。そうする
ことで、メイン操作のトランザクションが短くなります。

事前バインドを利用する場合

事前バインドを利用する場合、 CrmSvcUtil.exe を利用してコードを生成します。
この際、プラグイン内で必要なエンティティの情報のみを出力するようにしてください。
全ての情報を出力すると、それだけでファイルサイズが 5 - 10 MB 程度になります。

詳細はこちらの記事をご覧ください。
Dynamics CRM 2011 CrmSvcUtil ツールとその拡張方法 (フィルタリング)

まとめ

今回紹介した内容以外にも、パフォーマンスに関するベストプラクティスは数多く
存在します。次回はプラグインを実際に実行した際のパフォーマンスを測定する
方法を紹介します。

- Dynamics CRM サポート 中村 憲一郎