我正在构建一个现有应用程序的服务,其中每个服务的构建意图是它只由一个客户端使用,客户端和服务器都设置了双工通信通道。
限制
要求:
为了最初工作,我在两个客户端之间直接设置了一个IPC通道(netNamedPipeBinding),但我被告知要通过服务器发送所有内容。在大多数情况下,这种情况下的“服务器”与客户端在同一台机器上运行,所以我想出了这个非常粗略的概念验证尝试(见下面的代码块)。
问题:当为订阅服务调用方法时,当前服务的操作上下文(在其中调用该方法)为null - 这使得服务无需任何方式回调客户端
我正在考虑使用他在ServiceModelEx框架中提供的JuvalLöwy的发布/订阅框架,但是当所有客户端之间已经有他们自己和各自服务之间的双工通信设置时似乎没有必要...所以意图只是为了添加一个简单的发布/订阅层,它在概念上位于这些服务的“底层”,并且可以与任何需要订阅的人交谈。
欢迎提供建议和建设性的批评!
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;
}
}
答案 0 :(得分:1)
首先,我实施的模式似乎可归类为Mediator Pattern。
所以我通过传入FireEvent调用服务的当前实例上下文来解决这个问题,在我看来,它应该与订阅服务的上下文相同。
我在这里处理的情况是在同一用户和同一客户端机器的上下文中运行的断开连接的客户端应用程序,但是(根据要求)它们必须通过服务层进行通信。
我开始在他的ThreadPoolBehavior
库中使用WCF同步上下文和Juval Lowy的ServiceModelEx
类,但我与Ninject WCF Extensions阻碍的实现相关联。这个。
所以这个解决方案必须根据你自己的实现进行调整,但为了让你了解我如何使用它,这里是我更新的FireEvent
方法的要点:
public static void FireEvent( int sessionId, TData eventData, InstanceContext context )
{
var subscribers = Subscribers.Where( s => s.Key == sessionId );
var eventArguments = subscribers.Select( kvp => kvp.Value );
foreach ( var argument in eventArguments )
{
// set data associated with the event
argument.SetData( eventData );
NinjectInstanceProvider instanceProvider = null;
Object instance = null;
try
{
// get a "synchronized instance" of the service of type defined by event args
instanceProvider = new NinjectInstanceProvider( argument.ServiceType );
instance = instanceProvider.GetInstance( context );
// get the method from our "synchronized instance"
// filter by argument types so we don't run into any issues with ambiguity
var argumentTypes = new[] { typeof ( TEventArgs ) };
var method = instance.GetType().GetMethod( argument.Callback, argumentTypes );
// our method arguments
var arguments = new object[] { argument };
// invoke the method on our "synchronized instance"
method.Invoke( instance, arguments );
// release the instance
instanceProvider.ReleaseInstance( context, instance );
}
catch
{
// log
}
finally
{
if( provider != null )
{
if( instance != null ) { instanceProvider.ReleaseInstance( context, instance ); }
}
}
}
}