0

バックグラウンド:

NetTCP バインディングを使用して Windows サービス内で WCF サービスをホストするシステムがあります。コレクションに新しいサービスを追加するには、<system.serviceModel -> services /> 内に標準の WCF 構成エントリを追加し、サービスを初期化する必要があるホスティング フレームワークに通知するカスタム構成セクション内に行を追加します。各サービスは、独自のバックグラウンド スレッドと AppDomain インスタンスで初期化され、すべてが分離された状態に保たれます。

サービスの初期化方法の例を次に示します。

Host
  - ServerManager
    - ServiceManager 
      - BaseServerHost

ServerManager インスタンスには、標準の WCF 実装 (ServiceHost.Open/Close など) がある単一のサービス インスタンスにそれぞれ関連付けられている ServiceManagers のコレクションがあります。ServiceManager インスタンスは、BaseServerHost 基本クラス (抽象) を使用してサービスのインスタンスを (構成に基づいて - 標準のアセンブリ/型定義を持って) インスタンス化します。フレームワークがそれを使用できるようにするには、すべてのサービスがこれを継承する必要があります。初期化プロセスの一部として、BaseServerHost はいくつかのイベントを公開します。具体的には、所有する ServiceManager がアタッチする UnhandledException イベントです。(この部分は、以下の質問に関連して重要です。)

このプロセス全体は、私たちにとって非常にうまく機能します (1 つのインスタンスが 63 のサービスを実行しています)。なぜなら、WCF について何も知らない人を連れてきて、サービスを非常に迅速に作成できるからです。

質問:

私が遭遇した問題は、バックグラウンド スレッドに関するものです。エンドポイントで公開されているメソッドの大部分は、他のシステムへのメッセージの送信など、標準の挿入/更新/削除メソッド呼び出しの後にかなりの量のアクティビティを実行します。パフォーマンスを維持するために (フロントエンドは Web ベースです)、最初の挿入/更新/削除メソッドに処理を任せてから、バックグラウンド スレッドを起動して、エンド ユーザーが待つ必要のないすべてのものを処理します。完了します。このオプションは、そのバックグラウンド スレッドの何かが処理されず、Windows サービス全体がダウンするまでうまく機能します。

私のすべての調査に基づいて、グローバルな try/catch を実装する方法がないことがわかりました (バックグラウンド クラッシュの 1.1 処理を有効にするハッキングされた構成を使用することを除く)。 . それはさておき、私が見つけたのは、WCFホスティングのエンドポイント側で、各呼び出しで独自のスレッドにあるように見え、そのスレッドが「親」と通信するのは悪夢でした。サービスの観点から見たレイアウトは次のとおりです。

Endpoint (svc - inherits from BaseServerHost, mentioned above)
  - Business Layer
    - Data Layer

ビジネス レイヤーのバックグラウンド スレッドで例外をキャッチすると、それを Endpoint インスタンス (BaseServerHost から継承) にバブルアップし、この特定のサービス (インスタンス化した所有 ServiceManager によってアタッチされた) に対して BaseServerHost の UnhandledException イベントを発生させようとします。それ)。残念ながら、イベント ハンドラーはもう存在しないため、何もしません。これを機能させるために多くのことを試みましたが、これまでのところ、私の努力はすべて無駄になっています。

完全なモデル (以下に示す) を見ると、ビジネス層にその親エンドポイント (これは機能します) を認識させる必要があり、エンドポイントは実行中の BaseServerHost インスタンスを認識し、それをホストしている ServiceManager を認識する必要があります。エラーは、標準のログ記録手順で使用するために、これまで泡立てることができます。

Host
 - ServerManager
      - ServiceManager <=====================
           - BaseServerHost                ||
                - Endpoint (svc)           ||
                     - Business Layer <======
                          - Data Layer

私は運が悪い静的クラスを試してみましたが、ServerManager を静的にし、ServiceManagers の以前の内部コレクションを公開することさえしましたが (シャットダウンできるように)、そのコレクションも常に空または null です。

これを機能させることについての考えはありますか?

編集:もう少し掘り下げた後、私がこれをどのように機能させるかを正確に示す例を見つけました。標準の ASP.NET Web サイトでは、任意のページ/ハンドラーなどで、HttpContext.Current プロパティを使用して、その要求の現在のコンテキストにアクセスできます。これはまさに、そのサービスの所有 ServiceManager を返す「ServiceManager.Current」でこれを機能させたい方法です。おそらくそれが役立ちますか?

4

1 に答える 1

0

たぶん、CallContextで何かをすることを検討する必要があります:

http://msdn.microsoft.com/en-us/library/system.runtime.remoting.messaging.callcontext.aspx

ServiceManager を 1 つの物理スレッド (SetData) に関連付けるか、「論理」スレッド (LogicalSetData) に関連付けるかに応じて、SetData/GetData または LogicalSetData/LogicalGetData のいずれかを使用できます。LogicalSetData を使用すると、同じ ServiceManager インスタンスをスレッド内だけでなく、そのスレッドの「子」スレッド内でも使用できるようにすることができます。後で役立つ可能性のあるリンクをいくつか見つけたら、投稿しようとします。

これは、codeprojectの「仮想シングルトン パターン」へのリンクです。

ここに「スレッドシングルトン」へのリンクがあります

ここに「アンビエントコンテキスト」へのリンクがあります

これらのアイデアはすべて似ています。基本的に、静的な Current プロパティ (取得または取得/設定可能) を持つオブジェクトがあります。Current は、SetData ("Current" 値を現在のスレッドに関連付ける) または LogicalSetData ("Current" 値を現在のスレッドに関連付け、値を任意の「子」スレッド)。

HttpContext も同様の方法で実装されます。

System.Diagnostics.CorrelationManagerは、同様の方法で実装された別の良い例です。

Ambient Context の記事は、このアイデアで何ができるかをうまく説明していると思います。

CallContext について議論するときはいつでも、Jeffrey Richter のブログのこのエントリへのリンクも含めるようにしています。

最終的に、これがあなたに役立つかどうかはわかりません。マルチスレッド サーバー アプリケーションを使用している場合 (各要求がスレッドによって処理され、複数の要求が異なるスレッドで同時に処理される場合があります)、スレッドごとに ServiceManager があると便利です。その場合、ServiceManager を CallContext に格納するため、特定のスレッドに対して常に正しい ServiceManager インスタンスを返す ServiceManager に静的な Current メソッドを設定できます。このようなもの:

public class ServiceManager
{
  static string serviceManagerSlot = "ServiceManager";

  public static ServiceManager Current
  {
    get
    {
      ServiceManager sm = null;
      object o = CallContext.GetData(serviceManagerSlot);
      if (o == null)
      {
        o = new ServiceManager();
        CallContext.SetData(serviceManagerSlot, o);
      }
      sm = (ServiceManager)o;
      return sm;
    }

    set
    {
      CallContext.SetData(serviceManagerSlot, value);
    }
  }
}

プロセスの早い段階で、現在のスレッド (または現在の「論理」スレッド) で使用する ServiceManager を構成し、「Current」プロパティに格納することができます。

ServiceManager sm = new ServiceManager(thread specific properties?);
ServiceManager.Current = sm;

これで、コードで ServiceManager.Current を取得するたびに、現在実行中のスレッドの正しい ServiceManager になります。

この全体のアイデアは、実際にはあなたが望むものではないかもしれません.

あなたのコメントから、例外が発生した場合に取得しようとする CallContext データが null であると言っています。これはおそらく、CallContext データが設定されたスレッドとは異なるスレッドで例外が発生またはキャッチされていることを意味します。LogicalSetData を使用して、それが役立つかどうかを確認してみてください。

私が言ったように、これがあなたの助けになるかどうかはわかりませんが、うまくいけば、私は十分に明確であり(そして例も十分に明確です)、これらのアイデアがあなたの状況に当てはまるかどうかを知ることができます.

幸運を。

于 2011-02-08T23:09:40.217 に答える