2017-06-21 4 views
0

デュプレックスNetTcpサービスを作成したい。私は最良のアプローチが何であるか分かりません。 私は定期的にサーバーに状態を送信するクライアントを持っており、クライアント要求とは関係なく定期的にデータを送信するサーバーがあります。 私は2つの接続を避け、サーバー上のクライアントについて何も知らないので、クライアントによって開かれた接続を使用する必要があります。 クライアントが定期的にステータス情報を送信すると言ったように。 しかし、クライアントから確立された接続チャネルを、クライアントにデータを送信するために独立して使用するにはどうすればよいですか。また、サーバーからクライアントに送信されるデータには応答が必要です。WCF 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); 
    } 
} 

答えて

0

クライアントが確立した接続を使用する必要があります。これを実行するためには、いくつかの手順を実行する必要があります。

  1. は、あなたがあなたのサービスのためにPerSession(またはSingleton)インスタンスコンテキストモードを持っていることを確認してください。 PerCallは、クライアントとサーバー間の永続的な接続を維持することを許可しません。
  2. バインディングのReceiveTimeoutが十分に長いことを確認してください。アイドル状態の接続がWCFインフラストラクチャによって終了されないように、クライアント要求の間隔よりも長くする必要があります。
  3. サービスクラスでは、コールバックチャネルを覚えておく必要があります。これは、クライアントによって呼び出されるメソッドで実行する必要があります。あなたはSendNotification方法にあるときに、OperationContext.Current.GetCallbackChannel<IStatusServiceCallBack>()の結果はStatusServiceのプライベートフィールドに保存する必要があります。サービスのインスタンスモードがPerSessionの場合、各サービスクラスは1つのクライアントのみを持ちます。 Singletonサービスの場合は、コールバックのコレクションが必要です。
  4. コールバックメソッドの戻り値はOKですが、コールするにはコールバックチャネルオブジェクト(手順3で保存)が必要です。
  5. すべてのクライアントでコールバックメソッドを呼び出す場合は、すべてのクライアントコールバックをStatusServiceという静的フィールドに保持してから、すべてのコールバックメソッドを呼び出す必要があります。
  6. 特定のクライアントでのみコールバックメソッドを呼び出す場合は、クライアント(ID、名前など)を区別し、コールバックチャネルへの参照を辞書に保持する方法が必要です。サービスにPerSessionインスタンスコンテキストモードがある場合、サービスオブジェクトに直接アクセスすることはできません。したがって、クライアントを何とか区別して、静的なフィールドなどを介してアクセスすることをお勧めします。また、カスタムファクトリを注入してサービスオブジェクトを作成し、そのファクトリにアクセスすることもできます(ファクトリによってもこれらのオブジェクトがどこかに登録されていることが前提です)。

クライアントが切断すると、すぐにコールバックチャネルが無効にならないように注意してください。コールバックメソッドを呼び出すときにのみ例外が発生します。例外はスローされます。

関連する問題