简体   繁体   English

WCF NetTcp双工通道独立通信

[英]WCF NetTcp duplex channel independent communication

I want to create a duplex NetTcp service. 我想创建一个双工NetTcp服务。 I am not sure what is the best approach. 我不确定什么是最好的方法。 I have a client that periodically sends it's status to the server and I have a server that has to send periodically data that is independent of any client request. 我有一个客户端,该客户端定期将其状态发送到服务器,并且我的服务器必须定期发送独立于任何客户端请求的数据。 Because i want avoid two connections and don't know anything about the clients at the server, I have to use the connection that is opened by the client. 因为我要避免两个连接,并且对服务器上的客户端一无所知,所以我必须使用客户端打开的连接。 So like I said the client sends periodically status information. 因此,就像我说的那样,客户端会定期发送状态信息。 But how do I use the connection channel established from the client independantly for sending data to the client. 但是,我如何独立使用从客户端建立的连接通道将数据发送到客户端。 Also the data send from server to client does need a response. 另外,从服务器发送到客户端的数据确实需要响应。

[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);
    }
}

You're right that you need to use connection established by client. 没错,您需要使用客户端建立的连接。 In order to do this you have to perform several steps: 为此,您必须执行几个步骤:

  1. Make sure you have PerSession (or Singleton ) instance context mode for your service. 确保您的服务具有PerSession (或Singleton )实例上下文模式。 The PerCall one will not allow you to maintain permanent connection between client and server. PerCall不允许您维护客户端和服务器之间的永久连接。
  2. Ensure that ReceiveTimeout on your binding is long enough. 确保ReceiveTimeout上的ReceiveTimeout足够长。 It should be longer than period between client requests, so that idle connection is not terminated by WCF infrastructure. 它应该长于客户端请求之间的时间间隔,以便WCF基础结构不会终止空闲连接。
  3. In your service class you have to remember callback channel. 在服务类中,您必须记住回调通道。 This has to be done in the method that is called by client. 这必须在客户端调用的方法中完成。 So, the result of OperationContext.Current.GetCallbackChannel<IStatusServiceCallBack>() should be saved into private field of StatusService when you are in SendNotification method. 因此,当您使用SendNotification方法时,应将OperationContext.Current.GetCallbackChannel<IStatusServiceCallBack>()的结果保存到StatusService私有字段中。 If your service has PerSession instance mode, then each service class will have exactly one client. 如果您的服务具有PerSession实例模式,则每个服务类将只有一个客户端。 In case of Singleton service you need a collection of callbacks. 如果使用Singleton服务,则需要一组回调。
  4. It is OK to have return value for callback method, but you need a callback channel object (saved at step 3) to call it. 可以为回调方法提供返回值,但是您需要一个回调通道对象(在步骤3中保存)来调用它。
  5. If you want to call callback method on all clients, then you should keep all client callbacks in the static field of StatusService and then call method on all of them. 如果要在所有客户端上调用回调方法,则应将所有客户端回调保留在StatusService的静态字段中,然后在所有客户端上调用方法。
  6. If you want to call callback method only on particular client, then you need a way to distinguish clients (ID, Name, whatever) and keep references to callback channels in a dictionary. 如果只想在特定客户端上调用回调方法,则需要一种区分客户端(ID,名称等)并在字典中保留对回调通道的引用的方法。 In case your service has PerSession instance context mode you cannot access service object directly, so it is still good idea to distinguish clients somehow and access them via static field or something. 如果您的服务具有PerSession实例上下文模式,则无法直接访问服务对象,因此,最好还是以某种方式区分客户端并通过静态字段或其他方式访问客户端。 You can also inject your custom factory to create service objects and then have access to them (assuming that factory also registers these objects somewhere). 您还可以注入自定义工厂来创建服务对象,然后可以访问它们(假设工厂还在某个位置注册了这些对象)。

Beware that if client disconnects it does not invalidate callback channel immediately. 注意,如果客户端断开连接,它不会立即使回调通道无效。 You will find that out only when you call callback method - exception will be thrown back. 仅当调用回调方法时,您才会发现-异常将被抛出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM