在服务调用之间列出订阅者列表

时间:2012-02-01 02:37:42

标签: c# wcf

所以我创建了一个有回调的服务。像this这样的东西。它运行得很好,但我想做的是让任何已订阅的客户端被通知服务被调用(并将一些数据传递给回调函数)但是这并不像我想象的那么容易。

我创建了两个客户端,一个用于调用服务,另一个用于监听但是虽然我可以看到“监听器”(客户端1)订阅,但在随后的服务调用中(来自客户端2)订阅者列表为空(除了呼叫服务,也订阅)。我开始的第一个客户端不在订户列表中。我尝试了一些技巧来解决这个问题,所有这些都失败了。基本上我尝试的是一个黑客来创建一个静态类,保留一个静态的订阅者列表。

一些值得注意的要求。这必须是一个http绑定,所以我使用WSDualHttpBinding,我也使用安全令牌,所以协议是SOAP。我想知道在设置端点时我能做些什么吗?看起来这可能是一个好地方?我不确定。

那么,我如何获得订阅者列表,以便在调用我的服务时可以访问任何订阅的客户端?我猜想有一个很好的方法可以做到这一点,希望有人可以指出我正确的方向。

由于

1 个答案:

答案 0 :(得分:2)

我只能说我做了什么(我不知道它是不是很好的风格:)但它确实有效。)

我使用InstanceContextMode.Single创建服务

 [ServiceBehavior(
    InstanceContextMode = InstanceContextMode.Single,
    ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Service : IService
{}

我使用一个简单的字典来保存我的客户端“连接”,其中密钥是客户端“ID”。

private static Dictionary<GUID, IAdvServiceCallback> Subscribers;

我定义了订阅和取消订阅方法

    public bool Subscribe(GUID key)
    {
        try
        {
            if (Subscribers == null)
            {
                Subscribers = new Dictionary<GUID, IAdvServiceCallback>();
            }

            lock (Subscribers)
            {
                IServiceCallback callback = OperationContext.Current.GetCallbackChannel<IServiceCallback>();

                if (!Subscribers.ContainsKey(key))
                {
                    Subscribers.Add(key,callback);
                    ICommunicationObject obj = (ICommunicationObject)callback;
                    obj.Closed += SubscribedServiceClosed;
                    obj.Faulted += SubscribedServiceFaulted;
                }
                else
                {
                    //log subscriber is registered
                }
            }
            return true;
        }
        catch (Exception ex)
        {
            return false;
        }
    }


    public bool UnSubscribe()
    {
        try
        {
            if (Subscribers == null)
            {
                return true;
            }

            lock (Subscribers)
            {
                IServiceCallback callback = OperationContext.Current.GetCallbackChannel<IServiceCallback>();
                if (Subscribers.ContainsValue(callback))
                {
                    var row = Subscribers.Where(v => v.Value == callback).FirstOrDefault();

                    Subscribers.Remove(row.Key);
                }    
            }
            return true;
        }
        catch(Exception ex)
        {
            return false;
        }
    }

现在该服务可以向所有订阅者发送消息

Subscribers.Values.ToList().ForEach(delegate(IServiceCallback callback)
            {
                if (((ICommunicationObject) callback).State == CommunicationState.Opened)
                {
                   //send callback
                }
                else
                {
                   // remove subscriber because channel its not open anymore
                }
             });