2

私は、WCF を使用してサーバーとクライアントの間で通信するアプリケーションに取り組んでいます。サーバーには、クライアントが他のサービスに関する情報を照会し、マスター サービスからの情報を使用して必要なサービスをサブスクライブできる 1 つのマスター サービスと共に、サービスの数が変化しています。 .

マスター サービスは、サブサービスが変更 (追加、削除など) されると、サブスクライブしているクライアントに通知を送信します。また、サブサービスは数秒ごとに通知を送信します。

これは、WCF のコールバック チャネルを使用する絶好の機会のように思えますが、セッションを使用する必要があります。また、クライアントに通知を送信するときに、いずれかのクライアントが不当に切断された場合、サービスが停止し、通知しようとします。タイムアウトしたとしても、しばらくすると他のクライアントには通知されず、クライアントは実際にはサブサービスの背後にあるアプリケーションを監視するための GUI であるため、これは受け入れられません。また、送信操作が成功しなかった場合、サービスはすぐに知る必要があるため、MSMQ を使用することはオプションではありません。

私が思いついた解決策は、http バインディングを使用して (送信が失敗したときにすぐにわかるようにするため)、クライアントで明示的なコールバック サービスを作成することですが、それには見栄えの悪いインフラストラクチャ コードをたくさん書く必要があります。

だから、私の質問は次のとおりです。WCFでこれを行うより良い方法はありますか。最も見栄えの良いオプションは Callback Contracts でした。これにより、次のクライアントに送信する前に 1 つのクライアントからの ack を待つことができなければ、コールバック サービスを手動で管理する必要がなくなるからです。

4

1 に答える 1

3

私は同様の環境 (動的サービスなし) を使用しており、クライアント チャネルに障害が発生したときに非常によく似た問題が発生しました。私が思いついた最初の解決策は、コールバックを try/catch ステートメントでラップし、問題が発生した場合に問題のあるクライアントを削除することでしたが、これには問題があり、まったくスケーリングするようには見えませんでした。

私が最終的に行った解決策は、委任されたイベント ハンドラーを使用し、BeginInvoke を使用してそれを呼び出すことでした。CodeProject: WCF/WPF Chat Application (Chatters)ソリューションをまだ見ていない場合は、チェックすることをお勧めします。

ユーザーがログインすると、イベント ハンドラーが作成され、メイン イベントに追加されます。

public bool Login() 
{
    ...
    _myEventHandler = new ChatEventHandler(MyEventHandler);
    ChatEvent += _myEventHandler;
    ...
}

メッセージをブロードキャストする必要がある場合は常に、イベント ハンドラーが非同期で呼び出されます。

private void BroadcastMessage(ChatEventArgs e)
{
    ChatEventHandler temp = ChatEvent;
    if (temp != null)
    {
        foreach (ChatEventHandler handler in temp.GetInvocationList())
        {
            handler.BeginInvoke(this, e, new AsyncCallback(EndAsync), null);
        }
    }
}

リターンが戻ってくると、結果が処理され、何か問題が発生した場合、そのチャネルのイベント ハンドラーが削除されます。

private void EndAsync(IAsyncResult ar)
{
    ChatEventHandler d = null;
    try
    {
        //get the standard System.Runtime.Remoting.Messaging.AsyncResult,and then
        //cast it to the correct delegate type, and do an end invoke
        System.Runtime.Remoting.Messaging.AsyncResult asres = (System.Runtime.Remoting.Messaging.AsyncResult)ar;
        d = ((ChatEventHandler)asres.AsyncDelegate);
        d.EndInvoke(ar);
    }
    catch(Exception ex)
    {
        ChatEvent -= d;
    }
}

上記のコードは、Sacha Barberによって投稿された WCF/WPF チャット アプリケーションから (わずかに) 変更されています。

于 2008-12-04T15:18:38.373 に答える