如何从 WCF C# 中的托管进程调用 ServiceHost 的方法

How to call a method of the ServiceHost from the hosting process in WCF C#

我有一个由 Windows 服务托管的发布者/订阅者模式 WCF Duplex ServiceHost。 Windows 服务从单独的进程接收事件。 OnEvent 我想强制我的 WCF 主机将该数据发布到所有订阅的客户端。通常,如果客户正在调用,这很简单。但是,当我的服务主机需要执行此操作时,我无法理解如何执行此操作。 我有 2 个问题:

1:我不知道如何从我的 Windows 服务在 WCFHost 中创建一个通道,以便它可以用于发布到订阅者。

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) 构建..

"This CreateChannel overload cannot be called on this instance of DuplexChannelFactory, as the DuplexChannelFactory was initialized with a Type and no valid InstanceContext was provided."

所以我不确定如何执行此操作? 对于那些说阅读错误的人:是的,我阅读了错误。 现在如何使用不存在的 InstanceContext 执行此操作,因为此时 OperationContext.Current 不存在,因为我将此方法从我的托管进程调用到我的 WCFHost 中。

所以,如果我能有一个很好的例子来说明如何做到这一点 - 即使我必须使用 2nd link 的代码示例(当然是实现 DuplexChannelFactory),我也会非常感激。

编辑 基本上 windows 服务正在做一些繁重的工作来监视其他服务,大约每秒 2 次,然后它必须通过 WCF 将其发布到 "Subscribed" 客户端。

我认为您对所有内容如何连接在一起以及将客户端的概念与服务混合在一起感到非常困惑。您没有提供太多关于您的场景的具体信息,所以我将提供一个小示例,希望您能够将这些想法应用到您的问题中。

[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 迭代顺序中稍后将第二条较小的消息发送给客户端,然后再将第一条消息发送给客户端。此外,这不会扩展到大量客户端,因为您可以阻止一个客户端超时,从而阻止发送给其他客户端的消息。您可以使用类似于 Task 的东西来分派多个消息传递。如果这需要扩展,我建议查看 Reactive Extensions for .Net