5

Dynamics CRM 2011 オンプレミス。(ただし、この問題は、Dynamics CRM 以外の多くの状況に存在します。)

CRM プラグインにはエントリ ポイントがあります。

void IPlugin.Execute (IServiceProvider serviceProvider)

( http://msdn.microsoft.com/en-us/library/microsoft.xrm.sdk.iplugin.execute.aspx )

serviceProvider は、プラグイン実行コンテキストへの参照です。プラグインが行う便利な操作には、serviceProvider またはそのメンバーへのアクセスが必要です。

一部のプラグインは大きく複雑で、複数のクラスが含まれています。たとえば、複数回インスタンス化されるクラスを持つプラグインに取り組んでいます。このクラスは serviceProvider を使用する必要があります。

必要なすべてのクラスから serviceProvider へのアクセスを取得する 1 つの方法は、それらすべてのクラスにプロパティを追加してから、そのプロパティを設定することです。または、各クラスが必要とする serviceProvider の部分のプロパティを追加します。これらのアプローチのいずれも、多くの重複コードが発生します。

もう 1 つの方法は、スレッドのスコープにグローバル変数を設定することです。ただし、 http://msdn.microsoft.com/en-us/library/cc151102.aspxによると、「プラグインでグローバル クラス変数を使用しないでください」。

では、serviceProvider をあちこちに渡さずにアクセスする最善の方法は何でしょうか?

PS例が役立つ場合、 serviceProvider はロギングオブジェクトへのアクセスを提供します。ほとんどすべてのクラスをログに記録したい。ロギング オブジェクトへの参照をすべてのクラスに渡したくありません。

4

5 に答える 5

3

あなたが言うように、インスタンスはキャッシュされ、プラグイン パイプラインによってリクエスト間で再利用されるため、プラグインにメンバー変数を配置するべきではありません。

私が取るアプローチは、必要なタスクを実行するクラスを作成し、開発者ツールキット ( http://msdn.microsoft.com/en-us/library/hh372957 ) によって提供される変更された LocalPluginContext (パブリック クラスにする) を渡すことです。 .aspx ) コンストラクターで。その後、クラスは、他のコードの場合とまったく同じ方法で、その作業を実行する目的でインスタンスを格納できます。基本的に、プラグイン フレームワークによって課される制限から切り離されています。このアプローチでは、プラグイン パイプライン全体をモックするのではなく、クラスに実行コンテキストを提供するだけでよいため、単体テストも簡単になります。

開発者ツールキットで自動生成された Plugin.cs クラスに ServiceProvider プロパティが設定されないバグがあることに注意してください。LocalPluginContext のコンストラクターの最後に次の行を追加します。

this.ServiceProvider = serviceProvider;

プラグインで IoC アプローチの実装をいくつか見たことがありますが、私見ではプラグイン コードが複雑になりすぎます。スレッド/パフォーマンスの問題を回避するために、プラグインをスリムでシンプルにすることをお勧めします。

于 2013-10-01T21:03:07.947 に答える
2

このデザイン リクエストでは、私が心配することがいくつかあります (それが悪いということではなく、注意して予測する必要があるだけです)。

  1. IOrganizationService はマルチスレッド セーフではありません。IServiceProvider の他の側面も同様ではないと想定しています。
  2. IServiceProvider レベルでのテストは、追加のプロパティをモックする必要があるため、はるかに複雑です。
  3. 現在プラグイン内にあるロジックをプラグイン外で呼び出すことにした場合は、ログを処理するためのメソッドが必要になります (コマンド ライン サービスなど)。

オブジェクトをどこにでも渡したくない場合、簡単な解決策は、プラグインの実行時に設定できるクラスに静的プロパティを作成し、どこからでもアクセスすることです。

もちろん、上記の問題#1を処理する必要があるため、おそらく現在のスレッドのIDを使用してそのスレッドの値を設定および取得する、ある種のシングルトンマネージャーでなければなりません。そうすれば、プラグインが 2 回起動された場合でも、現在実行中のスレッドに基づいて正しいコンテキストを取得できます。(編集ファンキーなスレッドIDルックアップ辞書ではなく、@ shambulatorのThreadStaticプロパティが機能するはずです)

問題 2 については、そのまま保存するのではなく、別のプロパティ ( 、など)IServiceProviderに分割します。IPluginExecutionContextIOrganizationService

問題 3 については、オブジェクトの値自体ではなく、アクションまたは関数をマネージャーに保存する方が理にかなっている場合があります。たとえば、IPluginExecutionContext を格納するのではなく、ログに記録する文字列を受け入れ、IPlurginExeuctionContext を使用してログに記録する func を格納します。これにより、プラグイン内からの実行に依存することなく、他のコードが独自のログを設定できます。

于 2013-10-01T16:54:42.647 に答える
0

私はこれらのプラグインを自分で作成したことはありませんがIServiceProvider、I/O デバイスのように扱います。

そこから必要なデータを取得し、そのデータをプラグインに適した形式に変換します。変換されたデータを使用して、他のクラスを設定します。他のクラスから出力を取得し、IServiceProvider理解して使用できる用語に変換します。

入力と出力は に依存してIServiceProviderいますが、処理はそうである必要はありません。

于 2013-10-01T16:13:55.980 に答える
-1

エドゥアルド アヴァリア ( http://social.microsoft.com/Forums/en-US/f433fafa-aff7-493d-8ff7-5868c09a9a9b/how-to-avoid-passing-a-context-reference-among-classes ) から

まあ、SO の誰かがすでにあなたに言ったように、グローバル変数の制限があるため、同じコンテキスト (オブジェクト コンテキストとおそらく他の環境条件) 内で呼び出された場合、プラグインは再度インスタンス化されないため、カスタム グローバル変数は共有されます。ただし、コンテキストは同じになるため、多くのクラス間で共有する場合は、グローバル変数に割り当てても問題ありません。

とにかく、コンストラクターにコンテキストを渡し、それを共有してもう少し制御したいのですが、それは私だけです。

于 2013-10-02T08:45:54.747 に答える