所以我创建了一个有回调的服务。像this这样的东西。它运行得很好,但我想做的是让任何已订阅的客户端被通知服务被调用(并将一些数据传递给回调函数)但是这并不像我想象的那么容易。
我创建了两个客户端,一个用于调用服务,另一个用于监听但是虽然我可以看到“监听器”(客户端1)订阅,但在随后的服务调用中(来自客户端2)订阅者列表为空(除了呼叫服务,也订阅)。我开始的第一个客户端不在订户列表中。我尝试了一些技巧来解决这个问题,所有这些都失败了。基本上我尝试的是一个黑客来创建一个静态类,保留一个静态的订阅者列表。
一些值得注意的要求。这必须是一个http绑定,所以我使用WSDualHttpBinding,我也使用安全令牌,所以协议是SOAP。我想知道在设置端点时我能做些什么吗?看起来这可能是一个好地方?我不确定。
那么,我如何获得订阅者列表,以便在调用我的服务时可以访问任何订阅的客户端?我猜想有一个很好的方法可以做到这一点,希望有人可以指出我正确的方向。
由于
答案 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
}
});