如何从WCF C#

时间:2015-10-12 15:52:41

标签: c# .net wcf windows-services self-hosting

我有一个由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将其发布到“已订阅”的客户端。

1 个答案:

答案 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