2011-03-28 6 views
15

Webアプリケーションから消費しているWCFサービスがあります。使用しているクライアントは、Visual Studioの[サービス参照の追加]オプションを使用して生成されました。それはWebアプリケーションなので、アプリケーションの性質上、セッションが比較的短くなる可能性があるため、ユーザーがログインしてセッションの終了時にそれを保持すると、クライアントのインスタンスを作成することにしましたセッションが終了したときにその処理を処理します。フォールト状態に入った永続WCFクライアントの処理

これは私の疑問に繋がります。クライアントのチャンネルをフォールト状態にするのに最適な方法を決定しようとしています。我々は、このを作ってみたいくつかの周りを検索した後、:

if(client.State = CommuncationState.Faulted) 
{ 
    client = new Client(); 
} 

try 
{ 
    client.SomeMethod(); 
} 
catch //specific exceptions left out for brevity 
{ 
    //logging or whatever we decide to do 
    throw; 
} 

これ、しかし、サービスがダウンした場合でも、少なくとも私たちの場合には、クライアントが表示される、という事実のために動作しません。 Openは、実際に電話をかけてから、Faultedの状態になります。

これは私たちに何か他のことをさせるものです。私たちが思いついた別の選択肢は次のとおりです:

try 
{ 
    client.SomeMethod(); 
} 
catch 
{ 
    if(client.State == CommunicationState.Faulted) 
    { 
     //we know we're faulted, try it again 
     client = new Client(); 
     try 
     { 
      client.SomeMethod(); 
     } 
     catch 
     { 
      throw; 
     } 
    } 
    //handle other exceptions 
} 

しかし、それはにおいがします。明らかに、新しいクライアントを使用し、すべての呼び出しでそれを廃棄することで、これを回避できます。それは不必要だと思われますが、それが正しいとすれば、それが私たちが選ぶだろうと思います。だから、クライアントがフォールト状態にあるのかどうかを判断し、それについて何かしていることをうまく処理する最良の方法は何ですか?私たちは実際にすべてのコールに対して新しいクライアントを取得する必要がありますか?

クライアントのインスタンス化とすべてのチェックと処理は、クライアントのラッパークラスで行われます。私たちが意図したようにこれを行うと、アプリケーション自体は透過的です。呼び出しを行い、そこから例外を処理するには特別なコードは必要ありません。

+0

クライアントが障害状態になる原因は何ですか?私はいつもWCFサービスが正常に障害を返すようにしてきましたが、クライアントはそのビジネスについて継続することができます。サーバーが応答していないか、何か? – Tridus

+0

この場合、ASP.NETメンバーシップを使用しており、 "userIsOnlineTimeWindow"属性を超過して実行しました。明らかにそのような場合は、ユーザーをログインページにリダイレクトするだけですが、フォールト状態になる可能性のある他の状況に備えているかどうかを確認しようとしています。 – Zannjaminderson

答えて

18

あなたの質問に答えるために、あなたはこのようなのChannelFactoryプロパティのFaulted eventを扱うことができます。

一般的には、セッション中はチャンネルを開いたままにしないでください。終了したら、チャンネルを適切に終了してください(例外時には中止してください)。

また、可能であれば、Visual Studioの[サービス参照の追加]を使用しないでください。または、少なくとも生成されたコード/設定をクリーンアップすることを検討してください。プロキシー実装を使用する場合は、ClientBaseから派生して独自に作成するか、ChannelFactory実装を使用することをお勧めします。ラッパークラスについて言及しているので、ChannelFactoryを使用して、クリーンナップのニーズに応じてFaulted eventを処理することをお勧めします。

+0

答えをありがとう。私は、多くの人が各コールのクライアントチャンネルを開いたり閉じたりすることを話していましたが、そのような理由は何ですか? – Zannjaminderson

+2

その理由は、あなたのサービスへの並行コールと同時セッションが非常に多くしかないからです。したがって、あなたのWebアプリケーションのすべてのセッションにオープンセッションがある場合は、すぐにデフォルトの制限に達し、変更する必要があり、パフォーマンスが低下します。 これらの(その他の)設定を最適化する方法の詳細については、こちらをご覧ください。 http://msdn.microsoft.com/en-us/library/ee377061(v=bts.10).aspx – BrandonZeider

+0

ありがとうございました。私はChannelFactoryについてもう少し読んできました。そして、私たちはその方向を変えるように見えます。 – Zannjaminderson

11

は例えば、クライアントプロキシに.Faultedイベントを処理してみてください。

((ICommunicationObject)client).Faulted += new EventHandler(client_Faulted); 

private void client_Faulted(object sender, EventArgs e) 
{ 
    client = new Client(); 
    ((ICommunicationObject)client).Faulted += new EventHandler(client_Faulted); 
} 

それはあなたにそれを再オープンする機会を与え、瞬時にチャネルフォルトをトリガする必要があります。

また、try-catchブロックでclientメソッドへの各呼び出しをラップする必要があります。また、呼び出しをn回試行して失敗を記録するwhile()ループにラップすることさえあります。 EG:

私は限り client_Faultedイベントハンドラは clientプロキシを再作成する機会があったまでしばらく()ループを遮断するために ManualResetEventを使用するようにと行ってきた私のコードでは
bool succeeded = false; 
int triesLeft = 3; 
while (!succeeded && triesLeft > 0) 
{ 
    triesLeft--; 
    try 
    { 
     client.SomeMethod(); 
     succeeded = true; 
    } 
    catch (exception ex) 
    { 
     logger.Warn("Client call failed, retries left: " + triesLeft; 
    } 
} 
if (!succeeded) 
    logger.Error("Could not call web service"); 

。あなたはあなたがする必要があるものは何でもログ/クリーンアップを実行できるようにする必要があり

client.ChannelFactory.Faulted += new EventHandler(ChannelFactory_Faulted); 

+1

'Faulted'イベントからの退会はどうですか?それはどこで行なわれるべきですか? – itsho

関連する問題