I'm building a service into an existing application where each service was built with the intention that it would only be consumed by one client and the client and server are setup with duplex communication channels.
Limitations
- I don't have the option of re-designing that existing infrastructure
- I cannot use a shareable session
Requirement:
- I need to be able to communicate between client services (For instance, if a user clicks on an item and wants to share that item, the client, for whatever reason, might not be able to handle the "sharing" feature and needs to pass it on to another client to handle - this must be done through the service)
- Communication between clients must be conducted by the service.
To get this working initially, I setup an IPC channel (netNamedPipeBinding) directly between the two clients, but I was told to send everything through the server. The "server" in this scenario, in most cases, is running on the same machine as the client so I came up with this very crude proof of concept attempt (see below code block).
Issue: When a method is invoked for a subscribing service, the operation context for the current service (within which the method is being invoked) is null - this leaves the service without any way to call back to the client
I was considering using Juval Löwy's publish/subscribe framework that he provides in his ServiceModelEx framework, but it seemed unnecessary when all of the clients already have duplex communication setup between themselves and their respective services... so the intent is just to add a simple publishing/subscribing layer that sits conceptually "underneath" those services and can speak to any of them that care to subscribe.
Advice and constructive criticism is welcomed!
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;
}
}