2011-02-07 5 views
0

背景:WCF NetTCP with Background Threading

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

はサービスが初期化されている方法の例です:

Host 
    - ServerManager 
    - ServiceManager 
     - BaseServerHost 

ServerManagerのインスタンスは、標準のWCF実装嘘で、それぞれが単一のサービスインスタンスに相関ServiceManagersのコレクション(ServiceHost.Openを持っています/閉じるなど)。 ServiceManagerインスタンスは、BaseServerHost基本クラス(抽象的な)を使用して、サービスのインスタンスをインスタンス化します(設定に基づいて、標準アセンブリ/型定義を持ちます)。すべてのサービスは、それを使用できるようにするために、これを継承しなければなりません。 初期化プロセスの一環として、BaseServerHostは、いくつかのイベント、具体的には所有しているServiceManagerが接続するUnhandledExceptionイベントを公開します。

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

質問:

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

私の研究のすべてに基づいて、グローバルなtry/catch(バックグラウンドクラッシュの1.1処理を有効にするハッキングされた設定を使用しない)を実装する方法がないことがわかったので、私のチームは、適切な場所でそれを除いて、WCFのエンドポイント側で私が見つけたのは、各呼び出しで独自のスレッドにあるように見え、そのスレッドを「親」と話すことは悪夢でした。ここでは、サービスの観点からレイアウトです:

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

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

フルモデル(以下を参照)を見ると、ビジネス層に親エンドポイント(これは機能します)が分かるようにする必要があります。エンドポイントはServiceManagerについて知る必要がある実行中のBaseServerHostインスタンスこれをホスティングしているので、標準的なロギング手順で使用するために、これまでエラーをバブリングすることができます。

私はあまりにも運と静的クラスを試してみましたが、でも限りServerManagerのは、静的な作りとServiceManagersのその前に内部コレクションをexpotingとして行ってきました(そう、彼らがシャットダウンすることができます)が、そのコレクションは常に空またはnullできた
Host 
- ServerManager 
     - ServiceManager <===================== 
      - BaseServerHost    || 
       - Endpoint (svc)   || 
        - Business Layer <====== 
          - Data Layer 

この作品を作る上での考え方は?

編集:もう少し掘り下げた後、私はこの作業をどのように想像しているかの例を見つけました。標準のASP.NET Webサイトでは、任意のページ/ハンドラなどでHttpContext.Currentプロパティを使用して、そのリクエストの現在のコンテキストにアクセスできます。これは、「ServiceManager.Current」がそのサービスの所有するServiceManagerを返すようにするためには、これをどのように動作させたいのです。多分それが助けになるでしょうか?

答えて

0

たぶん、あなたはCallContextで何かをやってになります。

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

あなたはあなたのServiceManager、1つの物理スレッドに関連付けるかどうかに応じて、SetDataメソッド/ GetDataメソッドまたはLogicalSetData/LogicalGetDataのいずれかを使用することができます(SetData)または「論理」スレッド(LogicalSetData)を使用します。 LogicalSetDataを使用すると、スレッド内のほか、そのスレッドの「子」スレッド内で同じServiceManagerインスタンスを使用できるようになります。後で私がそれらを見つけることができるときに潜在的に便利なリンクのカップルを投稿しようとします。

codeprojectの"Virtual Singleton Pattern"へのリンクです。ここで

ここ"Thread Singleton"

へのリンクは、これらのアイデアのすべてが類似している"Ambient Context"

へのリンクです。基本的に、静的なCurrentプロパティ(getまたはget/set可能)を持つオブジェクトがあります。現在の値を現在のスレッドに関連させ、その値を任意の値に流すために、Currentはその値をCallContextに入れます( "Current"値を現在のスレッドに関連付ける)か、LogicalSetData( "Current" "子"スレッド)。

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

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

私はAmbient Contextの記事は、あなたがこのアイデアで達成できることを説明するのに非常に良い仕事だと思います。私はCallContextをdicsussたび

、私も最終的には、このentry from Jeffrey Richter's blog.

にこのリンクを含めるようにしようと、私はこれのうちのどれかがあなたを助けたりしませんかはわかりません。マルチスレッドサーバーアプリケーションがある場合(スレッドごとに要求が満たされ、異なるスレッドで複数の要求が同時に実行される可能性があります)、スレッドごとにServiceManagerがある可能性があります。その場合、CallManagerにServiceManagerを格納するため、常に特定のスレッドの正しいServiceManagerインスタンスを返すServiceManagerのstatic 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を設定し、「現在の」プロパティに格納されることがあります:

ServiceManager sm = new ServiceManager(thread specific properties?); 
ServiceManager.Current = sm; 
このような何か

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

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

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

私が言ったように、これがあなたを助けてくれるかどうかはわかりませんが、十分に明確になっています(例も十分明確です)。ない。

幸運。

+0

これは間違いなく高レベルから有望であり、私はそれが動作しない原因となっている実装方法だと思っています。サービス(BaseServerHost)が初期化された直後に、私はこれを行います: CallContext.SetData( "ApplicationName"、ApplicationName); CallContext.SetData(ApplicationName + "ServiceManager"、this); すぐに直接ウィンドウを使用すると、ServiceManagerインスタンスが表示されます。私は例外をキャッチすると、CallContext.GetData( "ApplicationName")はnullです。 私は間違って何かをしなければならないので、うまくいけば、あなたはこれを行うためのいくつかのリンクを見つけることができます。 – RubyHaus

+0

@digitall - 私はいくつかの情報といくつかのリンクを追加しました。私が考えていたアイディアが、あなたのシステムの仕組みに必ず当てはまるということは私には分かりません。私の答えには、あなたが話していることが当てはまるかどうかを知ることができるという十分な情報があります。 – wageoghe

+0

私はこれを忘れていません - 私は出張に呼ばれて、もう一週間ほど見直されません。私はその時さらに少し掘り下げていくつもりです。 – RubyHaus

関連する問題