我有一个由Windows服务托管的发布者/订阅者模式WCF Duplex ServiceHost。 Windows服务从单独的进程接收事件。 OnEvent我想强制我的WCF主机将该数据发布到所有订阅的客户端。通常,如果客户正在呼叫,这是直截了当的。但是,当我的服务主机需要这样做时 - 我无法理解如何做到这一点。 我有两个问题:
1:我不知道如何从我的Windows服务在WCFHost中创建一个Channel,以便它可以用来发布给订阅者。
2:我读了Creating WCF ChannelFactory所以我知道我正在创建一个DuplexChannelFactory(每秒2个),这可能是太多的开销。
任何帮助示例,非常感谢提示。我不是WCF专家,目前对它的了解比我认为我应该知道的更多。
我读过SO Can I call a Method in a self hosted wcf host locally?
然后我在我的WCFHost中创建了一个方法,如下所示:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession,
AutomaticSessionShutdown = false,
IncludeExceptionDetailInFaults = true)]
[CallbackBehavior(UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class ServerHost<TService> : ServiceHost where TService : class
{
public T GetDuplexClientChannel<T, Cback>(BindingType bindingType, EndpointAddress endPointAddress) where T : class
{
ServiceEndpoint sep = GetContractServiceEndPoint<T>(bindingType, endPointAddress);
lock (_syncRoot)
{
DuplexChannelFactory<T> factory = new DuplexChannelFactory<T>(typeof(Cback), sep);
return factory.CreateChannel(endPointAddress);
}
}
}
我得到一个错误,当然没有InstanceContext因为我正在构建使用typeof(Cback)..
“无法在此DuplexChannelFactory实例上调用此CreateChannel重载,因为DuplexChannelFactory已使用Type初始化,并且未提供有效的InstanceContext。”
所以我不确定如何才能执行此操作? 对于那些说读错误的人:是的,我读错了。 现在如何使用不存在的InstanceContext来实现,因为此时不存在OperationContext.Current,因为我将此方法从我的托管进程调用到我的WCFHost中。
所以,如果我有一个很好的例子来说明如何做到这一点 - 即使我必须在第二个链接上使用代码示例(当然实现DuplexChannelFactory),我将不胜感激。
修改 基本上,Windows服务正在做一些繁重的工作来监控其他服务,大约每秒2次,然后必须通过WCF将其发布到“已订阅”的客户端。
答案 0 :(得分:1)
我认为您对所有内容的连接方式感到非常困惑,并将客户端的概念与服务混合在一起。您还没有提供有关您的方案的更多具体信息,所以我将提供一个小例子,希望您能够将这些想法应用到您的问题中。
[ServiceContract(CallbackContract=typeof(IMyServiceCallback))]
public interface IMyService
{
[OperationContract]
void Register();
}
public interface IMyServiceCallback
{
[OperationContract]
void ReceiveData(string data);
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class MyService : IMyService
{
static HashSet<IMyServiceCallback> s_allClients = new HashSet<IMyServiceCallback>();
static object s_lockobj = new object();
public void Register()
{
lock(s_lockobj)
{
_allClients.Add(OperationContext.Current.GetCallbackChannel<IMyServiceCallback>());
}
}
public static void SendDataToClients(string data)
{
HashSet<IMyServiceCallback> tempSet;
lock(s_lockobj)
{
tempSet = new HashSet<IMyServiceCallback>(_allClients);
}
foreach(IMyServiceCallback cb in tempSet)
{
try
{
cb.ReceiveData(data);
}
catch(Exception)
{
lock(s_lockobj)
{
_allClients.Remove(cb);
cb.Abort();
cb.Dispose();
}
}
}
}
}
在OnEvent方法中,您可以在事件方法中调用与此类似的内容。
MyService.SendDataToClients(mydata);
这使用静态数据来存储客户端列表。如果您想要为不同的端点划分客户端,则需要做一些不同的事情。如果在前一个调用尚未完成时可以再次调用OnEvent方法,则此代码可能存在无序消息和扩展问题。例如,如果您收到2条消息,第一条消息很大而第二条消息很小,您可能会在稍后以HashSet迭代顺序向客户端发送第二条较小的消息,然后再发送第一条消息。此外,这不会扩展到大量客户端,因为您可以阻止一个客户端的超时,阻止将消息发送到其他客户端。您可以使用类似于任务的东西来分派多个消息传递。如果需要扩展,我建议查看Reactive Extensions for .Net