2012-07-06 4 views
5

クライアントアプリケーションから、(および(パラメータ)を実行するための操作とパラメータを含む)+トランザクションIDをリモートキューに送信しています。リモートサーバーは要求をある時点でデキューし、処理に時間がかかります。"コールバックディスパッチャ"コンポーネントのためのより良いデザインが必要

処理が完了すると、クライアントキュー(アプリケーション応答+トランザクションIDを含む)で応答が送信されます。これは、クライアントがマップできる唯一の方法である完全に「切断」通信モードです要求に対する応答はtransactionIDを介して行われます。

メッセージ応答はクライアント側でデキューされ、(transactionIDに基づいて)元の要求と一致します。

私が今やっていることは、クライアントがリクエストをサーバーキューにポストすると、transactionIdとコールバック(デリゲート)を保持している辞書にコールバックを追加することです。これは、トランザクション結果をコールバックするコールバックにトランザクションIDをマッピングするDictionary<int, object>です。

コールバック/デリゲートは、要求に応じてコールバック代理人の署名が異なるため、オブジェクトとして格納されます(たとえば、応答がList<string>を返し、別の応答がintを返す可能性があります)。

クライアントキューはレスポンスのデキュー時に、応答のタイプ(したがってコールバックの対応するシグニチャ)を認識します。したがって、transactionIDに基づいてディクショナリからコールバックを取得します。次に、オブジェクトを対応するデリゲート型にキャストし、コールバックを呼び出します。

私はこのアプローチがあまりセクシーではないが、私は実際にそのようなタスクを実行する別の方法を見ていない。

これを実行する方法はありますか?

問題が十分に解明されない場合は、私に知らせてください。

+0

[C#:RandomとOrderByは良いシャッフルアルゴリズムを使用していますか?](http://stackoverflow.com/questions/1287567/c-is-using-random-and-orderby-a-good-shuffleアルゴリズム) – Arion

答えて

3

リアクティブエクステンションは、そのような種類のメッセージングに便利なツールです。

まず、レスポンスにIMessageのようなインタフェースや基本クラスを実装します。応答の各種類は、その後、あなたのメッセージキューがIObservable<IMessage>を実装作るここ

public interface IMessage 
{ 
    int TransactionId { get; } 
} 

public class UserListMessage : IMessage 
{ 
    int TransactionId { get; set; } 
    public List<string> Users { get; set; } 
} 

のように別々のクラスにカプセル化する必要があります。リアクティブエクステンションは、Subject<T>と呼ばれるすぐに使用できる実装を提供します。あなたはそれをラップしたいかもしれません。

Observableは、オブザーバを内部リストのどこかに格納する方法を実装しています(Subscribe(IObserver<IMessage> observer))。新しいレスポンスが到着すると、サブスクライブされたオブザーバごとにOnNext(IMessage message)メソッドが呼び出されます。与えられたトランザクションIDを持つタイプUserListMessageのメッセージのためのコールバックを登録します

var subscription = myQueue 
    .OfType<UserListMessage>() 
    .Where(msg => msg.TransactionId == id) 
    .Subscribe(callback); 

最後に、あなたの応答ハンドリング登録コードは、次のようになります。 おそらくあなたはどこかで購読を拒否したいと思うでしょう。それは:

subscription.Dispose(); 

これはRxでどのように見えるか簡単なサンプルでした。さあ、もっと詳細なチュートリアルを見つけてください。

1

取得可能なすべての応答の種類を定義する列挙型をクライアント側で作成できます。次に、列挙の各値を特定の関数呼び出しに関連付ける大きな「選択ケース」を含む関数をコーディングできます。 次に、辞書を使用してtransactionIDを、サーバーから取得する応答の種類を示す列挙値に関連付けます。

各タイプのレスポンスに実装する必要のある機能の種類に応じて、よりオブジェクト指向の方法を見つけることができます。 多分、あなたは基本クラスResponseActionを作成できます。一般的なレスポンスメソッドを使用して、取得可能なレスポンスタイプごとにこのクラスを継承してから、サーバーを呼び出すと、正しいResponse_Specific_Actionクラスをインスタンス化し、このインスタンスをディクショナリに配置してから各レスポンスで辞書を使用して適切なインスタンスを見つけ、同じ標準のレスポンスメソッドを呼び出すと、Response_Specific_Actionの「特定の」実装が使用されます。

ResponseActionクラスのルートを使用する場合は、transactionIDを基本クラスのプロパティとして含めることも考えられます。

1

あなたは状況が何となく分かりません。まず第一に、どの通信メカニズムがクライアントサーバーのトランザクション中に使用されているかについては言及していませんでしたか? WCFとその 'コールバックチャネル'を使用していますか?

すべてのトランザクションに関するいくつかの共通データを持つ基本クラスの下にすべてのリクエスト応答メッセージをラップするのはなぜですか?

あなたはあなたの辞書のリストを使用していますが、応答はトランザクションごとに異なるので、なぜオブジェクトなのでしょうか?すべての応答メッセージに対して共通の契約を結ぶことは難しくありませんか?クライアントとサーバー間の通信フローについて少しお教えください

1

これはアダプタパターンの問題とまったく同じです。アダプタの概要については、this linkを参照してください。

あなたがする必要があるのは、クライアントの応答(それが何であれ、List<string>またはintを含む)をカプセル化する抽象化を作成することです。あなたの抽象化は、さまざまな振る舞いがすべて同じシグネチャでカバーされるように、範囲が十分に広くなければなりません。このような何か:

その後
public abstract class MessageCompleteHandler 
{ 
    public abstract void Execute(); 
} 

//name this one better, just an example :) 
public class ListOfStringHandler : MessageCompleteHandler 
{ 
    public override void Execute() 
    { 
     //get list of strings 
     // do something with it 
    } 
} 

public class MessageCompleteHandlerFactory 
{ 
    public MessageCompleteHandler GetHandler(int transactionId) 
    { 
     //this replaces/uses your dictionary to match handlers with types. 
    } 
} 

、あなたが応答を取得する場合、あなたは適切なハンドラオブジェクトを作成するために、トランザクションIDを使用して、それを実行します。もちろん、あなたのハンドラの種類がかなり少ない場合には、これは最適です。

+0

いいですが、ここでアダプタはどこですか? – Pein

+0

MessageCompleteHandlerの実装は、さまざまなデリゲートのアダプタです。様々な署名を単一のインターフェースに適合させる。 – tallseth

+0

サンプルに代理人はありません。私が望むならあなたのソリューションを実装する方法がわからないと思います。現在は、AdapterではなくCommandパターンのように見えます。 – Pein

関連する問題