6

最近、Dynamics CRM 2011で1つのプラグイン実行(つまり、Execute()メソッドのパス)が同じスレッド上にとどまることが保証されているかどうかという質問が出ました。CRM 2011プラグインのスレッディング/アンビエントコンテキスト

私はAmbient Contextパターンを使用してトレースを実装して、トレースしたいクラスにトレースサービスを渡さないようにしたいと考えています。問題は、プラグインが登録されたステップごとに1回のみインスタンス化され、その後同じインスタンスからのすべての後続操作に対応することがわかっていることです。つまり、現在のITracingServiceインスタンスを割り当てるTracing.Currentのような静的なプロパティを持つことはできません。これを実行すると、最後に開始された操作によって、まだ実行中の他のすべての操作のインスタンスが上書きされます(この種の同時実行性は珍しくありません)。私はExecute()方法は同じスレッドに残っているの下にあるすべてのものを確認することができれば

今、私はまだ、静的フィールドに[ThreadStatic]属性を利用周囲コンテキストを使用することができます。

public static class Tracing 
{ 
    [ThreadStatic] 
    private static ITracingService _current; 

    public static ITracingService Current 
    { 
     get 
     { 
      if (null == _current) 
      { 
       _current = new NullTracingService(); 
      } 

      return _current; 
     } 

     set { _current = value; } 
    } 
} 

私が入る時にこれを設定しますExecute()メソッドを呼び出し、最後にクリアすると、トレースサービスインスタンスへの参照が削除されます。

種類の MSCRMプラグインのコンテキストでのスレッドについては、個々のスレッドがThreadPoolから来ていることがわかります - 私の問題に関してどのような影響がありますか。

MSCRMプラグインを使用してスレッディングがどのように処理されるかについての深い洞察がありますか?この特別なケースではSOLIDコードを使用してトレースのクロスカット問題をどのようにエレガントに処理できるかについての他のアイデアはありませんか(AOP /オプションはこちら)?

ありがとうございました。

+0

スレッドセーフな方法で実行することについての懸念は理解していますが、なぜ同じスレッドで実行することに懸念があるのか​​分かりません。もう少し説明できますか? – Daryl

+0

さて、別のスレッドにプラグインの実行を移動させないで、独自のITracingServiceインスタンスを再度「接続」する必要はありません。このような場合にThreadStaticがどのように処理されるかはまだわかりません。 – TeaDrivenDev

答えて

3

シンプルでスマートな答え:あなたがそれをすると痛い場合は、それをしないでください。 :)

Ambient Contextパターンを使用するための自己申告要件は、CRMの設計パターンと競合しています。 CRMがどのように機能するかを考えてみましょう。IServiceProviderをトレースサービスを含めて必要なものすべてに渡します。それは複雑なマルチスレッドと最適化をすべて処理し、派手なパターンや静的な変数やスレッディングトリックでそれを超越しようとはしません。

同じパターンを使用することをお勧めします。IServiceProviderを必要なクラスまたはメソッドに渡してください。ずっと簡単ですが、後で変わったバグがあるときは、マイクロソフトのエンジニアを凌駕しているかどうかは疑問に思わないでしょう。 :)

+0

私は、物事をあまりにも遠くに置くことや、使用するように設計されていない方法でシステムを使用することに常に注意する必要があることに同意します。トレースサービスに関わる「複雑なマルチスレッド」がどのようにあるのかはわかりません。それはそこにあるか、そうでないだろう - 私が探しているのは、それが確実であることを確認する方法です。 ;-)ところで、自己申告された要件は、実際には良い、保守可能なソフトウェア設計です。 Ambient Contextは終わりの手段に過ぎず、可能ならばそれを使わずに済ませて喜んでいます。 – TeaDrivenDev

+0

毎回IServiceProviderからトレースサービスを抽出するコードを記述するのではなく、Tracing.Currentを書くことができますか?もしそうなら、Tracingサービスへの参照を簡単に取得するServiceProviderオブジェクトのC#拡張メソッドを記述することをお勧めします。また、ボイラープレートコードを貼り付けるコードスニペットを使用してください。変更する可能性は低くなります。変更すると、単純な検索/置換が行われます。何よりも、10分以上も費やして、実際のビジネス上の問題を解決し始めてください。私はあなたがこれについて心配することを支払っていないとうれしいです! :) –

0

私は恐らく全体のプラグイン/スレッド/静的な問題をここで推測することができますが、あなたが提案するものは少し複雑に思えます。代わりに、トレースリスナーを使用することを検討しましたか?

アプリケーション全体でTrace.Writelineを使用すると、単一のトレースリスナーがすべてのメッセージをキャプチャします。そうすれば、トレースオブジェクトを渡す必要はありません。例えば

Execute(...) 
{ 
    if(System.Diagnostics.Trace.Listeners 
     .Count(l => typeof(l) == MyCustomTraceListener) == 0) 
    { 
     System.Diagnostics.Trace.Listeners.Add(new MyCustomTraceListener()); 
    } 

    DoWork(); 
} 

DoWork() 
{ 
    System.Diagnostics.Trace.WriteLine("I'm doing work!"); 
} 

関連リンク:

Trace ListenersWalkthrough: Creating a Custom Trace Listener

+0

私はそれらについて読んだが、それらを完全に退ける。私はそれをすべてのプロセス/ AppDomain、右に登録されているかかりますか?同じプラグインインスタンス上で 'Execute()'を呼び出すたびに、それ自身のITracingServiceインスタンスが生成され、そのインスタンスを1つだけ使用することが保証されなければなりません。私が探しているのは、実際に各クラスがその作業を行うために必要とされないパラメータで、ほとんどの私のコンストラクタを汚染することなく確実に行う方法です。 – TeaDrivenDev

+0

私は頭の上からわからない、私はMSDNを掘る必要があります。私はあなたの状況を理解しています。プロセス/ AppDomainビットについて考えてみましょう。 –

0

CRMは、単一のプラグインオブジェクトを作成し、要求を処理するために、必要に応じてスレッドを使用しています。あなたが確かめることができる唯一のことは、単一のプラグインオブジェクトのために一度に複数のスレッドを実行することです。

スレッドはIISによって管理され、可能であれば再利用されます。したがって、毎回Executeが呼び出されることを確実にしたい場合は、新しいITracingServiceを設定する必要があります。 Executeが呼び出されるたびに、1つしかないことを確認するには、ifステートメントを実行して確認する必要があります。

バッキング変数はThreadStaticなので、スレッドの問題については心配する必要はありませんが、IISはスレッドを再利用しようとするため、Executeが呼び出されるたびに空ではありません。

関連する問題