WCF NetTcp双工通道独立通信

时间:2017-06-21 12:23:47

标签: wcf nettcpbinding duplex-channel

我想创建双工NetTcp服务。我不确定什么是最好的方法。 我有一个客户端定期将其状态发送到服务器,我有一个服务器,必须定期发送独立于任何客户端请求的数据。 因为我想避免两个连接,并且对服务器上的客户端一无所知,我必须使用客户端打开的连接。 就像我说客户端定期发送状态信息一样。 但是如何使用从客户端建立的连接通道来独立地向客户端发送数据。从服务器发送到客户端的数据也需要响应。

[ServiceContract(CallbackContract = typeof(IStatusServiceCallBack))]
public interface IStatusService
{
    [OperationContract]
    void SendStatus(int statusCode, string statusMessage);
}

public interface IStatusServiceCallBack
{
    // I know IsOneWay=true cannot work, but how to return value????
    [OperationContract(IsOneWay = true)]
    int SendPayTransaction(PayTransaction payTransaction);
}

public class StatusService : IStatusService
{
    public IStatusServiceCallBack Proxy
    {
        get
        {
            return OperationContext.Current.GetCallbackChannel
            <IStatusServiceCallBack>();
        }
    }

    public void SendNotification(int statusCode, string statusMessage)
    {
        Console.WriteLine($"\nClient status : {(statusCode)} {statusMessage}");
    }
    // Is this possible???
    public int SendPayTransaction(PayTransaction payTransaction){
        return Proxy.SendPayTransaction(payTransaction)
    }

}


class Program
{
    static void Main(string[] args)
    {
        var svcHost = new ServiceHost(typeof(NotificationService));
        svcHost.Open();
        bool closeService = false;
        do{
            string command = Console.ReadLine();
            if(command == "Send"){
               // Is this possible???????
               int result = svcHost.SendPayTransaction(new PaymentTransaction(){Amount = 5.50});
               Console.WriteLine($"Result of payment : {result}");
            } else if (command == "exit"){
               closeService = true;
            }
        }while(!closeService);
    }
}

1 个答案:

答案 0 :(得分:0)

您是正确的,您需要使用客户建立的连接。为此,您必须执行以下几个步骤:

  1. 确保您的服务具有PerSession(或Singleton)实例上下文模式。 PerCall将不允许您维护客户端和服务器之间的永久连接。
  2. 确保绑定上的ReceiveTimeout足够长。它应该比客户端请求之间的时间长,因此WCF基础结构不会终止空闲连接。
  3. 在您的服务类中,您必须记住回调频道。这必须在客户端调用的方法中完成。因此,当您使用OperationContext.Current.GetCallbackChannel<IStatusServiceCallBack>()方法时,StatusService的结果应保存到SendNotification的私有字段中。如果您的服务具有PerSession实例模式,则每个服务类将只有一个客户端。如果是Singleton服务,您需要一组回调。
  4. 可以使用回调方法的返回值,但需要一个回调通道对象(在步骤3中保存)来调用它。
  5. 如果要在所有客户端上调用回调方法,则应将所有客户端回调保留在StatusService的静态字段中,然后对所有客户端调用方法。
  6. 如果您只想在特定客户端上调用回调方法,那么您需要一种方法来区分客户端(ID,Name,等等)并在字典中保留对回调通道的引用。如果您的服务具有PerSession实例上下文模式,则无法直接访问服务对象,因此以某种方式区分客户端并通过静态字段或其他方式访问它们仍然是个好主意。您也可以注入自定义工厂来创建服务对象,然后可以访问它们(假设工厂也在某处注册这些对象)。
  7. 请注意,如果客户端断开连接,则不会立即使回调通道无效。只有在调用回调方法时才会发现 - 异常将被抛回。