2016-07-15 16 views
1

WPFとWCFを使用してクライアント/サーバーアプリケーションを開発しています。 サーバーアプリケーションは、何らかの問題が発生したときにクライアント要求を実行してコールバックするWCFサービスをホストします。長時間実行されている操作でビジー状態のときにWCFサービスへのPINGの応答

サービスインターフェイスでは、すべてのOneWay操作のデュプレックスコールバック契約が定義されています。

(簡体字)IService

[ServiceContract(CallbackContract = typeof(ISrvServiceCallback))] 
public interface ISrvService 
{ 
    [OperationContract(IsOneWay = true)] 
    void Ping(); 

    [OperationContract(IsOneWay = true)] 
    void LongRunningOperation(); 
} 

public interface ISrvServiceCallback 
{ 
    [OperationContract(IsOneWay = true)] 
    void PingReply(); 

    [OperationContract(IsOneWay = true)] 
    void LongRunningOperationStatus(string reply); 
} 

サービスは、クライアントの呼び出しに応じて状態を変更するいくつかのオブジェクトをmantainする必要があります。このため私はシングルトンサービスを持つことに決めました。

(簡体字)サービス

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] 
public class SrvService : ISrvService 
{ 
    MyObject statusObject; 

    public void LongRunningOperation() 
    { 
     //calling back the client reporting operation status 
     OperationContext.Current.GetCallbackChannel<ISrvServiceCallback>() 
     .LongRunningOperationStatus("starting long running application"); 

     statusObject.elaborateStatus(); 

     //calling back the client reporting object status 
     OperationContext.Current.GetCallbackChannel<ISrvServiceCallback>() 
     .LongRunningOperationStatus("object status: " + statusObject.ToString()); 
    } 

    public void Ping() 
    { 
     OperationContext.Current.GetCallbackChannel<ISrvServiceCallback>().PingReply(); 
    } 


    public SrvService() 
    { 
     statusObject= ...statusObject init... 
    } 

} 

あなたは、サーバアプリケーションが利用可能であるかどうかをチェックするために、クライアント・コール(5秒毎)私はサービスによって公開さのPing操作を持って見ることができるようにネットワーク(各クライアントはサーバー接続アイコン赤色 =サーバーがありません。緑色 =サーバーが利用できません)。

クライアントが長時間実行される操作を要求すると、サーバはその操作に取り組んで開始し(が赤に変わり、クライアントのサーバー接続のアイコン)ping要求に応答することができません。

長時間実行操作が終了したら、)サーバーは、に、クライアントによって行われたすべての要求を返信し、サーバ接続のアイコンは緑色に引き返します。

長時間の操作が実行されている場合でも、サーバーが常にping要求に応答するようにサービスを開発する方法を知りたいと思います。

  • 私はそれが私が サービスのオブジェクトの状態をmantainする InstanceContextMode.Singleを維持する必要があることを考慮して行うことができますどのように?
  • WCFサービスにpingを実行して の可用性を確認し、結果をクライアントに視覚的に表示する方法がありますか?

答えて

1

シングルトンサービスでは、少なくとも、別のスレッドでLongRunningOperationを実行する必要がありますが、必要な動作を得るためにサーバーインスタンスのマルチスレッド実装が必要になります。この操作が本質的にスレッドセーフでない場合は、実装内のロックまたはセマフォなどを使用して複数の同時呼び出しを防ぐ必要があります。クライアントがLongRunningOperation()を呼び出すと、別のスレッドで実行され、ping要求に自由に応答できます。

これを実装する方法はたくさんあります。ちなみに、クライアントは非同期呼び出しを行っているようです(LongRunningOperationが返るのを待っている間にping要求を出しているようです)ので、非同期プログラミングの知識があると仮定します。WCFにはbuilt in ways of handling concurrencyというものがありますが、ほとんどのドキュメントではシングルトンのインスタンスは扱いませんので、注意深く読んでその特殊なケースに焦点を当てる必要があります。

私は(herehereを参照)非同期/のawaitパターンで最も成功を収めてきた - これが正しく設定されたら、私はステートフルなシングルトンサービスで実行時間の長いサービス呼び出しのための非常に信頼性が高く、予測可能なパターンを持っていました。

また、pingに関しては、単にユーザーの接続ステータスを表示しているだけで、コントロールに使用する予定がある場合(電話をかける前にサービスがオンラインかどうかを確認する) there is a lot of discussions here on why you should avoid it.

EDIT:クイック例非同期で/

[ServiceContract] 
public interface ISrvService() 
{ 
    [OperationContract] 
    bool Ping(); // doesnt need to be async 

    [OperationContract] 
    Task<string> LongRunningOperation(); 
} 
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] 
public class SrvService : ISrvService 
{ 
    MyObject statusObject; 

    public async Task LongRunningOperation() 
    { 
     // lock/semaphore here if needed 
     await Task.Run(() => statusObject.elaborateStatus()); // you could impliment elaborateStatus() as an async Task method and call it without Task.Run 
     return statusObject.ToString(); 
    } 

    public bool Ping() 
    { 
     return true; 
    } 


    public SrvService() 
    { 
     statusObject= ...statusObject init... 
    } 

} 
を待ちます10クライアントを使用して
public class SrvClient : ClientBase<ISrvService> 
{ 
    public async Task<string> LongRunningOperation() 
    { 
     return await base.Channel.LongRunningOperation(); 
    } 

    public async Task<bool> Ping() 
    { 
     // note that we still call this with an await. In the client we are awaiting the wcf service call 
     // this is independent of any async/await that happens on the server 
     return await Task.Run(() => base.Channel.Ping()); 
    } 
} 

public class SomeApplicationClass() 
{ 
    SrvClient Client; 
    DispatcherTimer PingTimer; 

    public SomeClass() 
    { 
     BasicHttpBinding binding = new BasicHttpBinding(); 
     EndpointAddress endpoint = new EndpointAddress(
      "http://...:8000/Service/Address"); 
     OutpostClient = new OutpostRemoteClient(binding, endpoint); 

     // pingTimer setup 

    } 

    // async voids are scary, make sure you handle exceptions inside this function 
    public async void PingTimer_Tick() 
    { 
     try 
     { 
      await Client.Ping(); 
      // ping succeeded, do stuff 
     } 
     catch // specify exceptions here 
     { 
      // ping failed, do stuff 
     } 
    } 

    public async Task DoTheLongRunningOperation() 
    { 
     // set busy variables here etc. 
     string response = await Client.LongRunningOperation(); 
     // handle the response status here 
    } 
} 

またthis answerは、関連すると思われます。

+0

返信いただきありがとうございます@ plast1k!私は非同期に関する小さな知識を持っており、実際にその分野も探っています。 クライアントは、_ThreadPool.QueueUserWorkItem(checkService)_を呼び出す_DispatcherTimer_を使用してサービスにpingを実行します。 _checkService_は_serviceClient.Ping()_を呼び出します。 あなたが投稿したすべてのリンクを見て、自分の問題をどのように解決できるかを見ていきます。 async/awaitシングルトンサービス実装のサンプルコードを用意することは可能でしょうか?クライアントから電話をかけてサーバーから返信する方法を知りたいだけです。 – aDone

+0

問題ありません。私は後でそれを掘ることができるはずです、私は私がそれを見つけると私の投稿を編集します。 – plast1k

+0

@a例が追加されました。 – plast1k

関連する問題