各サービスが 1 つのクライアントによってのみ消費され、クライアントとサーバーが二重通信チャネルでセットアップされることを意図して構築された既存のアプリケーションにサービスを構築しています。
制限事項
- その既存のインフラストラクチャを再設計するオプションはありません
- 共有可能なセッションを使用できません
要件:
- クライアント サービス間で通信できるようにする必要があります (たとえば、ユーザーがアイテムをクリックしてそのアイテムを共有したい場合、クライアントは何らかの理由で「共有」機能を処理できない可能性があり、渡す必要があります。処理するために別のクライアントに送信します - これはサービスを介して行う必要があります)
- クライアント間の通信は、サービスによって行われる必要があります。
これを最初に機能させるために、2 つのクライアント間で IPC チャネル (netNamedPipeBinding) を直接セットアップしましたが、すべてをサーバー経由で送信するように言われました。このシナリオの「サーバー」は、ほとんどの場合、クライアントと同じマシンで実行されているため、この非常に大雑把な概念実証の試みを思い付きました (以下のコード ブロックを参照)。
問題: サブスクライブしているサービスに対してメソッドが呼び出されると、(メソッドが呼び出されている) 現在のサービスの操作コンテキストが null になります。これにより、クライアントにコールバックする方法がなく、サービスが終了します。
私は、Juval Löwy が ServiceModelEx フレームワークで提供しているパブリッシュ/サブスクライブ フレームワークを使用することを検討していましたが、すべてのクライアントが自分自身とそれぞれのサービスとの間で二重通信のセットアップを既に行っている場合は不要に思われました。概念的にこれらのサービスの「下」に位置し、サブスクライブしたいサービスと通信できるパブリッシング/サブスクライブ層。
アドバイスと建設的な批判を歓迎します!
public static class SubscriptionManager<TEventArgs>
where TEventArgs : class
{
private static ConcurrentDictionary<int, Action<TEventArgs>> _subscribers =
new ConcurrentDictionary<int, Action<TEventArgs>>();
// sessionId is NOT the WCF SessionId
public static void FireEvent( int sessionId, TEventArgs eventArgs )
{
var subscribers = _subscribers.Where( s => s.Key == sessionId );
var actions = subscribers.Select( keyValuePair => keyValuePair.Value );
foreach ( var action in actions )
action.BeginInvoke( eventArgs, action.EndInvoke, null );
}
public static void Subscribe(int sessionId, Action<TEventArgs> eventHandler)
{
_subscribers.TryAdd(sessionId, eventHandler);
}
public static Action<TEventArgs> Unsubscribe(int sessionId)
{
Action<TEventArgs> eventHandler;
_subscribers.TryRemove(sessionId, out eventHandler);
return eventHandler;
}
}