2

パブリッシュ-サブスクライブ パターンで WCF サービスを作成しています。

誰かがイベントを発行したときに、すぐにすべてのクライアントに送信したくありません。

クライアントごとに、そのクライアントにその公開について通知する必要があるかどうかを確認できるようにしたいと考えています。

基本的に、これはデータベースにアクセスし、そのクライアントがそれらのパラメーターを使用してその特定のイベントをサブスクライブしているかどうかを確認することによって行われます (事前に行うことはできません。データベースに対してのみ確認する必要があります)。

現在、この List-Based Publish-Subscriberサンプルを使用して作業していますが、イベントが発行されると、クライアント セッションが個別にトリガーされてメッセージが送信されるように動作します。

だから今のところ、私はこれを変更しています:

 public void PriceChangeHandler(object sender, PriceChangeEventArgs e)
 {
     _callback.PriceChange(e.Item, e.Price, e.Change);
 }

これに:

 public void PriceChangeHandler(object sender, PriceChangeEventArgs e)
 {
     // Perform some database checks using BL if this client needs to be notified about this event

     // Only if answer is YES - call the callback function on that client
     _callback.PriceChange(e.Item, e.Price, e.Change);

     // Also - send the client an EMAIL + SMS
     _emailServer.SendEmail(e.Item);
     _smsServer.SendSMS(e.Item);
 }

2 つの質問:

これは正しい方法ですか?そして、「この」クライアントが何であるかを知るにはどうすればよいですか? クライアントは、保存する「subscribe」メソッドで資格情報を送信する必要がありますか? または、プリンシパルを格納するカスタム 'UsernameValidator' を実装する必要がありますか?

また、BL に送信するすべてのクライアントの静的リストを用意する必要はありません。BL は、メッセージを送信する必要があるクライアントのみを返します。

4

2 に答える 2

3

最初にこの質問に答えると、生活がずっと楽になると思います。

そして、「この」クライアントが何であるかを知るにはどうすればよいですか?

OperationContext.Current.GetCallbackChannel<T>

サービスが受信する呼び出しごとに、呼び出しが行われるクライアント チャネルが存在します。これにより、その呼び出しを行ったクライアントのコールバック チャネルのみが得られます。これは、クライアントを区別できる簡単な方法です。 .

全体としてのシナリオへのアプローチに関して、あなたが提案したように、最初にリストをsubscribers静的に保存dictionaryしますが、各クライアントのコールバックインスタンスをユーザー名とともに保持します。

private static Dictionary<IPriceChangeCallback, string> subscribers = new Dictionary<IPriceChangeCallback, string>();

IPriceChangeCallbackコールバック コントラクトはどこにあり、文字列は一意のユーザー名または任意の識別子である可能性があります。これで、クライアントを区別する基本的な機能が得られました。たとえば、最後に受信したメッセージを、送信したクライアントを除くすべてのクライアントに公開したい場合は、次のようにします。

        lock (subscribers)
        {
            foreach (var _subscriber in subscribers)
            {
                if (OperationContext.Current.GetCallbackChannel<IPriceChangeNotification>() == _subscriber.Key)
                {
                      //if the person who sent the last message is the current subscriber, there is no need to
                      //publish the message to him, so skip this iteration
                        continue;
                }
                else
                {
                       //GetCurrrentClient is a handy method, you can optionally include this  
                       //in your callbacks just to let your clients know who exactly sent the publication
                        _subscriber.Key.PriceChangeCallback(e.Item, e.Price, e.Change, GetCurrentClient());
                }
             }
         }

または、理想的にはデータベースにも持っている必要があるユーザー名に基づいてクライアントを区別します。

            lock (subscribers)
            {
                foreach (var _subscriber in subscribers)
                {
                    if(_subscriber.Value == "Jimmy86"))
                    {
                        //Identify a specific client by their username and don't send the notification to him
                        //here we send the notification to everyone but jimmy86
                        continue;
                    }
                    else
                    {
                        _subscriber.Key.PriceChangeCallback(e.Item, e.Price, e.Change, GetCurrentClient());
                    }
                }
            }

繰り返しになりますが、誰がサービス操作を呼び出したかを知りたいときはいつでも、その特定のメッセージを送信したのは誰であるかをクライアントに伝えたい場合は、GetCurrentClient()前述の方法を使用してください。

    private string GetCurrentClient()
    {
        return clients[OperationContext.Current.GetCallbackChannel<IPriceChangeNotification>()];
    } 

これは正しい方法ですか?

上記のアプローチがどれほど賢明かはわかりませんが、クライアントのリストを保持してそれらに対して何らかのメソッドを呼び出したいと思ったときはいつでもそうしました。

クライアントは、保存する「subscribe」メソッドで資格情報を送信する必要がありますか?

はい、これは一般的な方法の 1 つです。サービスをSubscribe()操作します。これは、クライアントがサービスに参加したいときに最初に呼び出すメソッドになります。

        [OperationContract(IsOneWay = true)]
        public void Subscribe(string username)
        {
            lock (subscribers)
            {
                subscribers.Add(OperationContext.Current.GetCallbackChannel<IPriceChangeNotification>(), username);
            }
        }

私は数か月前に Pub/Sub Silverlight サービスに取り組んでいましたが、この記事とそれに付随するビデオが非常に貴重であることがわかりました。

于 2012-06-21T22:52:48.487 に答える
0

私が思いついた答えは、「カスタム UsernamePasswordValidator」を実装することです。これにより、各サービス インスタンスは、接続されているクライアントを認識できるようになります (この方法では、Subscribe で何も渡す必要はありません)。

「発行」イベントが到着すると、対象のユーザーを確認します (同じユーザーが複数のマシンから接続している可能性があります)。

次に、ターゲット ユーザーで「PriceChangeEvent」を発生させ、すべてのクライアント インスタンスに対して「PriceChangeHandler」イベントを発生させます。

次に、イベント内で、ログに記録されたプリンシパルが対象のユーザーであるかどうかを確認し、そうであれば、クライアント マシンでコールバック関数を呼び出します。

これにより、接続されているクライアントのリストを保存する手間が省け、'Subscribe' メソッドで何も渡す必要もありません。

于 2012-06-23T07:15:38.807 に答える