2016-03-28 11 views
0

私はC#の初心者です。サードパーティのネットワークライブラリを使用して要求を送信する小さなプログラムを開発します。C#で同期呼び出しとして動作するように非同期呼び出しを変換する方法

キューにqTasksという名前のリクエスト(単純な文字列)が格納されていて、そのリクエストを1つずつ順番に処理して実行中にキューを更新することができますエラーが返されました。

私はちょうどforループを使用して配列内のsend requestコマンドを1つずつ呼び出すことができますが、残念ながらsendrequestコマンドはコールバックOnStageChangedの非同期メソッドであり、次のリクエストを送信する前に結果を確認する必要があります。ステータスは「完了」です。

私は今、それを処理するために、以下の方法を使用しています:いつでもステージの変化コールバックメソッドOnStageChangeHandlerは、ライブラリによって呼び出されます、メインUIスレッドで

// Put those request text in a queue names qTasks, then call a goNextTask() to process the request one by one. 
// The queue can be updated by the UI thread at anytime, goNextTask will be called periodically to handle those pending request in the queue. 

private void goNextTask(bool lastSuccess = true) 
{ 
    if (lastSuccess) 
    { 
     if (qTasks.Count > 0) 
     { 
      // continue to next request 
      string requestText = qTasks.Dequeue(); 
      SendRequest(requestText, OnStageChangeHandler); 
     } else { 
      // Report for all request sent successfully 
     } 
    } else { 
     // stop and show error 
    } 
} 

を、それ完了すると「完了」状態になります。

private void OnStageChangeHandler(object sender, StageChangeEventArgs e) 
{ 
    if (e.newState == SessionStates.Done) 
    { 
     // check result here 
     bool success = <...> 

     // then call the goNextTask in UI thread with the result of current request. 
     Application.Current.Dispatcher.BeginInvoke(
      System.Windows.Threading.DispatcherPriority.Normal, 
      (Action)(() => goNextTask(success))); 
    } 
} 

それは今も元気に動作しますが、私はそれが多少再帰的な流れがあるとして、それは少し愚かだと思う(A - > B - > A - > B - >を....)。

私は、MSがウェブリクエストの処理を改善したので、シンクモードで動作できることを知りました。

それはそのようなループのような単純な流れで行うことができるように私は、私は同期呼び出し、上記のように非同期呼び出しを動作させるためのラッパーを持つことができるかどうかを知りたいのです:

while (qTaks.Count > 0) 
{ 
    if (!sendAndWaitReturn(qTasks.Dequeue())) { 
     // Report error and quit 
    } 
} 
// all tasks completed 

このsendAndWaitReturnメソッドは、要求を送信し、 "完了"のステータスを待ってから、結果を返します。

Iは、現在の要求のステータスを示すために制御フラグを使用することができるいくつかの例を発見し、コールバック関数が、この制御フラグを更新し、whileループを使用して、このフラグにUIスレッドがループ中:

while (!requestDone); 

nextRequestまでrequestDoneまで続きません。しかし、この場合、UIはブロックされます。

UIスレッドをブロックせずに同期呼び出しとして動作するように非同期呼び出しを変換する方法はありますか?

+0

SendRequestメソッドで処理されるwhatsの例を挙げることはできますか?これを行うには再帰が最善の方法です。しかし、論理に基づいて、その書き方を変えることができます。 – Thanigainathan

+0

SendRequestメソッドは、ライブラリによって提供されます。実際、FiddlerCoreのSendRequestメソッドでは、必要なヘッダーとrequestBodyBytesがキュー内のデータから生成されます。 –

+0

何か、もし 'SendRequest'が返ってきたら?それは 'タスク'を返しますか?しかし、これを同期させても、UIスレッドでこれを実行するとUIがフリーズすることを理解していますか? –

答えて

0

あなたが苦労しているのは、矛盾した欲望があるということです。一方では、UIスレッドをブロックしないようにする必要があります。一方、非同期に動作させたくないので、UIスレッドをブロックすることになります。

あなたは1つを選ぶ必要があります。特に(UIスレッドをブロックするという観点から)同期させることは絶対にありません。あなたがそれをするときに痛いなら、はそれをしないでください。

あなたは指定していませんが、この処理をボタンクリックイベントから開始していると思います。そのクリックイベントが非同期で呼び出されるようにします。例:

private async void StartProcessing_Click(object sender, EventArgs e) 
{ 
    await Task.Run(() => StartProcessing()); 
} 

ここで処理が開始され、UIスレッドは結ばれていません。

次は、あなたが正しいということです。イベントは周期的なやり方で愚かです。イベントは、状態が変更されたことを誰かに通知することです。その目的はキューポリシーを管理することではありません。 キューは、キューポリシーを管理する必要があります(または、それを抽象化しない場合は、を処理するメソッド)。

どうすればよいですか?さて、あなたはSendRequestがセッションオブジェクトを呼び出し元に返すと言ってきました。呼び出し元は、キューポリシーを編成し、SendRequestを再度呼び出すかどうかを決定していると思われます。

呼び出し元にセッションオブジェクトの有効性を確認させ、それに基づいて継続するかどうかを決定します。

さらに、私はその特定のライブラリには慣れていませんが、簡単に、同じ署名付きのSendRequestAndWait()メソッドがあり、必要に応じてよりよく聞こえるかもしれないと思われるドキュメントを見ています。

+0

アドバイスをいただきありがとうございます。 実際、送信要求プロセスは、UIボタンまたはタイマーイベントによってトリガーされます。アプリケーション内で一緒に実行されている他のプロセスがあり、特定のイベント(たとえば、計算プロセスの完了後)で要求を要求キューに送信します。また、ユーザーはUIでリクエストを直接追加することもできます。そのため、リクエストを送信するときにUIをブロックしたくないのです。送信要求プロセスは、あらかじめ定義された期間内にキュー内のリクエストを送信します。または、UI内のボタンクリックによってトリガーされます。 –

+0

SendRequestAndWaitメソッドは、私が探しているもののように聞こえます。しかし、SendRequestAndWaitメソッドが実際に "done"まで待つかどうかはわかりません。OnStageChangeのコールバックもありますが、コールバックメソッドを使用して呼び出し元に通知していますが、ヘルプファイルには詳細がありません。多分私はそれを後で試してみるでしょう。どうもありがとう。 –

+0

テストしたところ、SendRequestAndWaitは実際に動作します。それでもコールバックを使用して呼び出し元に通知しますが、ステータスが「完了」になるまで待機します。デバッガでチェックしたところ、次のステートメントを実行する前にステータスが「完了」のOnStageChangeHandlerが終了します。ありがとう。 –

関連する問題